Prévia do material em texto
Arquitetura do Sistema
O projeto de desenvolvimento dos sistemas institucionais possui um grande escopo
de atuação, por consequência, exige um conjunto de requisitos funcionais e não
funcionais complexos demandados à arquitetura de software. Para solução de tal
problema, foi modelada uma arquitetura multicamadas utilizando Java/JEE e um
conjunto de frameworks auxiliares visando o incremento de qualidade.
Metas e Restrições da Arquitetura
No contexto de uma instituição dos moldes da Universidade Federal do Rio Grande
do Norte, onde co- existem diversos sistemas e há uma heterogeneidade de
processos e lógicas de negócios nas mais relacionadas áreas, é de suma
importância que um software seja modelado de forma a obedecer a princípios
arquiteturais que favoreçam a implementação de regras como segurança,
privacidade, portabilidade, distribuição, reutilização etc.
A arquitetura foi elaborada com as seguintes restrições:
● Interoperabilidade: Um dos requisitos não funcionais mais importantes é a
integração entre os sistemas institucionais (SIPAC/SCO, SIGRH, SIGAA). Por
exemplo, os sistemas acadêmico (SIGAA) e o administrativos (SIPAC)
necessitam de dados relacionados aos recursos humanos da instituição para
o correto funcionamento de diversas funcionalidades. Dessa forma, ao invés
desses dados serem alimentados também no SIGAA e SIPAC, eles são
recuperados dos dados lançados no sistema de recursos humanos (SIGRH).
Uma outra exigência é que a base de dados de login e senha dos usuários
para autenticação em todos os sistemas seja a mesma. Assim, um usuário
que acessa os três sistemas não precisam de logins e senhas distintos para
seus acessos.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
1
● Segurança: A segurança é feita no nível de autenticação e autorização. A
autenticação é realizada baseada em usuário e senha. Já a autorização é
implementada usando o conceito de usuários, papéis e subsistemas, como
detalhado na Figura 4.1. Cada sistema está associado a um conjunto de
subsistemas. Cada subsistema possui um conjunto de papéis. Os papeis são
permissões para um conjunto de operações no sistema. Um usuário pode
assumir um conjunto de papéis, através de permissões. Isso lhe dá acesso
aos subsistemas e as operações indicadas pelo papel.
● Escalabilidade: Os sistemas institucionais são utilizados por toda a
universidade. Dessa forma, é necessário que o sistema seja capaz de atender
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
2
adequadamente a uma variação populacional lenta ou súbita. A
escalabilidade horizontal é desejável para resolver a variação lenta.
● Alta Disponibilidade: A utilização do sistema em funções administrativas,
acadêmicas e de recursos humanos exige do mesmo uma alta
disponibilidade, uma vez que os sistemas são utilizados para o auxílio à
execução das diversas tarefas de cada área.
● Implementar Complexidade de Infra-Estrutura (Abstrair Complexidade): A
arquitetura de software deve abstrair os elementos mais críticos/complexos do
software, de forma a tornar o desenvolvimento dos subsistemas e seus
respectivos casos de uso mais simples.
Tecnologias Utilizadas
Um conjunto de tecnologias é utilizado para o desenvolvimento das operações dos
sistemas institucionais, entre elas:
● Hibernate 3.2: framework utilizado para a realização do mapeamento objeto
relacional. O objetivo do Hibernate é diminuir a complexidade entre os
programas Java, baseado no modelo orientado a objeto, que precisam
trabalhar com um banco de dados do modelo relacional.
● Java Server Faces 1.2/ RichFaces 3.3.3: framework que implementa o padrão
MVC (Model, View, Controller) utilizado para o desenvolvimento web com
Java.
● Struts 1.2: framework que implementa o padrão MVC (Model, View,
Controller) utilizado para o desenvolvimento web com Java. No início do
desenvolvimento dos sistemas institucionais, Struts era o framework para
desenvolvimento Web que estava mais evidente. Dessa forma, escolheu-se
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
3
esta tecnologia para os desenvolvimentos dos casos de uso. Hoje em dia,
todos os casos de uso desenvolvidos usam a tecnologia Java Server Faces.
● EJB 2.1: é um dos principais componentes da plataforma JEE (Java
Enterprise Edition). É um componente do tipo servidor que corre no container
para EJB do servidor de aplicação. Os principais objetivos da tecnologia EJB
são fornecer um rápido e simplificado desenvolvimento de aplicações Java
baseado em componentes distribuídas, transacionais, seguras e portáveis.
Atualmente encontra-se na versão 3.0. Os sistemas institucionais utilizam a
versão 2.1 juntamente com o padrão de projetos EJB Command.
● Spring 3.1.2: é um framework open source não intrusivo, baseado nos
padrões de projeto inversão de controle (IoC) e injeção de dependência. É
utilizado basicamente para que a declaração dos Managed Beans, usados no
desenvolvimento com JSF, seja feita através de anotações e também para a
simplificação de acesso ao banco de dados com JDBC, usando
JDBCTemplate.
● JBoss 4.2.2: é um servidor de aplicação de código fonte aberto baseado na
plataforma JEE implementada completamente na linguagem de programação
Java.
Separação em Camadas
A arquitetura elaborada para o desenvolvimento dos sistemas institucionais utiliza a
abordagem de separação em camadas. O intuito é não misturar as
responsabilidades dos componentes dos sistemas, onde cada componente deve ter
suas responsabilidades bem definidas. As camadas são utilizadas para realizar esta
organização, agrupando os componentes com funcionalidades afins em camadas
semelhantes.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
4
As camadas são organizadas em forma de pilhas e obedecem uma hierarquia. Em
geral, as camadas mais acima da hierarquia dependem das camadas mais abaixo.
Apenas as camadas adjacentes podem se comunicar entre si e uma camada inferior
não pode depender de uma camada superior. De acordo com a Figura 5.1, cada
camada representa:
● Apresentação: utilizada para a exibição de informações em janelas ou
páginas HTML. É nela que há a manipulação de requisições do usuário e de
requisições HTTP. Considerando os componentes do desenvolvimento web,
podemos listar Managed Bean, Actions, JSPs, Servlets.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
5
● Aplicação: delega trabalho da camada de apresentação para a camada de
domínio. Adiciona serviços (transações, por exemplo) ao sistema.
Componentes: Façades, EJB Commands.
● Domínio/Negócio: representa a lógica de negócio dos sistemas.
Componentes: classes de domínio e processadores (realizam a persistência).
● Infra-Estrutura/Acesso a Dados: permite a comunicação com a base de
dados, disponibiliza serviços de mensagens, etc.
Camada de Persistência (Infra-Estrutura/Acesso a
Dados)
O banco de dados utilizado para a persistência dos dados envolvidos nos sistemas
institucionais é o PostgreSQL (www.postgresql.org). A camada de persistência foi
modelada com base no padrão de projeto Data Access Object (DAO) e o framework
Hibernate, realizando assim, o mapeamento objeto relacional.
O Hibernate é um framework de mapeamento objeto relacional para aplicações
Java, ou seja, é uma ferramenta para mapear classes Java em tabelas do banco de
dados e vice-versa. É bastante poderoso e dá suporte ao mapeamento de
associações entre objetos, herança, polimorfismo, composição e coleções.
O Hibernate não apresenta apenas a função de realizar o mapeamento objeto
relacional. Também disponibiliza um poderoso mecanismo de consultade dados,
permitindo uma redução considerável no tempo de desenvolvimento da aplicação.
Na camada de persistência, também é utilizado um pool de conexões, que é
gerenciado pelo servidor de aplicações utilizado (JBoss). É utilizado o protocolo
X/Open XA, permitindo que os vários bancos sejam acessados dentro de uma
mesma transação.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
6
A Listagem 6.1 apresenta a configuração do arquivo
/server/default/deploy/postgres-ds.xml no diretório de instação do JBoss. Nesta
configuração são indicadas configurações do banco com base no protocolo X/Open
XA, juntamente com o tamanho do pool de conexões.
<xa-datasource>
<jndi-name>jdbc/SIPACDB</jndi-name>
<xa-datasource-class>org.postgresql.xa.PGXADataSource</xa-datasource-class>
<xa-datasource-property name="ServerName">servidor.info.ufrn.br</xa-datasource-property>
<xa-datasource-property name="PortNumber">5432</xa-datasource-property>
<xa-datasource-property name="DatabaseName">administrativo</xa-datasource-property>
<xa-datasource-property name="User">sipac</xa-datasource-property>
<xa-datasource-property name="Password">*****</xa-datasource-property>
<track-connection-by-tx/>
<min-pool-size>1</min-pool-size>
<max-pool-size>50</max-pool-size>
</xa-datasource>
Os sistemas institucionais são formados por três bancos de dados:
● ADMINISTRATIVO: base de dados para armazenar dados relacionados aos
sistemas administrativos e de recursos humanos.
● ACADÊMICO: base de dados para armazenar dados relacionados ao sistema
acadêmico.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
7
● COMUM: base de dados com informações comuns a todos os sistemas, como
por exemplo, a base de dados para autenticação de usuários, cadastro de
permissões, entre outras.
Algumas tabelas comuns a todos os sistemas são replicadas entre as 3 bases de
dados. Por exemplo, em cada um desses bancos existe uma tabela USUARIO que
possui informações sobre os usuários que podem se autenticar nos sistemas. É
importante saber que no momento em que, pela a aplicação, um dado é inserido em
um dos bancos de dados, automaticamente esta informação é sincronizada para os
outros dois.
Utilização do Padrão DAO
O padrão de projeto DAO desvincula dos usuários da arquitetura a dependência do
framework de mapeamento utilizado, abstraindo e encapsulando todo um acesso a
uma fonte de dados. Dessa forma, é possível realizar alterações na forma de
mapeamento sem causar impacto nos casos de uso, já que garante a independência
do mecanismo de persistência.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
8
A interface GenericDAO, ilustrada pela Figura 6.3, possui a definição genérica de
todos os métodos que uma classe DAO deve conter.
Basicamente a interface GenericDAO é formada pelos seguintes métodos:
Session getSession(): retorna um objeto do tipo org.hibernate.Session que
representa a conexão entre a aplicação e a fonte de dados, através do Hibernate.
void create(PersistDB obj): as entidades que terão informações de objetos
persistidas devem implementar a interface br.ufrn.arq.dominio.PersistDB, disponível
na arquitetura dos sistemas. Este método é responsável por realizar a persistência,
através do Hibernate, de objetos de classes que implementam esta interface.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
9
void remove(PersistDB obj): é responsável por remover da base de dados
informações mapeadas em objetos de classes que implementam a interface
PersistDB.
void update(PersistDB obj): é responsável por atualizar na base de dados
informações mapeadas em objetos de classes que implementam a interface
PersistDB.
PersitDB findByPrimaryKey(int id, Class classe): dados os valores de chave primária
(id) e o tipo da classe (classe), retorna um objeto que representa a linha na tabela
com valor de chave primária igual a id da tabela do banco de dados mapeada pela
classe definida por classe.
Collection<PersitDB> findAll(Class classe): retorna uma coleção de objetos que
representam todas as linhas da tabela mapeada pela classe definida por classe.
Collection<PersitDB> findByExactField (Class classe, String field, Object value):
retorna uma coleção de objetos que representam linhas da tabela mapeada pela
classe definida por classe e que possuem a coluna mapeada pelo atributo field com
o valor value passado como argumento.
Collection<PersitDB> findByLikeExactField (Class classe, String field, Object value):
retorna uma coleção de objetos que representam linhas da tabela mapeada pela
classe definida por classe e que possuem a coluna mapeada pelo atributo field com
o valor value passado como argumento, desde que este valor apareça em qualquer
parte dos dados presentes na coluna.
Collection<PersitDB> findByLikeExactInitField (Class classe, String field, Object
value): retorna uma coleção de objetos que representam linhas da tabela mapeada
pela classe definida por classe e que possuem a coluna mapeada pelo atributo field
que iniciam com o valor value passado como argumento.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
10
void update(Class<?> classe, Integer id, String campo, Object valor): atualiza a
coluna mapeada pelo atributo campo da linha da tabela mapeada pela classe classe,
de valor de chave primária igual a id com o valor value passado como argumento.
A classe GenericDAOImpl é uma classe concreta que implementa a interface
GenericDAO, contendo a implementação de todos os seus métodos.
Criando um Objeto DAO
Cada sistema possui uma classe DAO que centraliza todos os DAOs criados nos
sistemas: GenericSipacDAO, GenericSigaaDAO e GenericSigrhDAO.
public class GenericSipacDAO extends GenericDAOImpl {
public GenericSipacDAO() {
super(Sistema.SIPAC);
}
}
public class GenericSigrhDAO extends GenericDAOImpl {
public GenericSigrhDAO() {
super(Sistema.SIGRH);
}
}
public class GenericSigaaDAO extends GenericDAOImpl {
public GenericSigaaDAO() {
super(Sistema.SIGAA);
}
}
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
11
No SIPAC, a criação de DAOs utiliza uma abordagem de existência de interfaces
abstratas para cada DAO existente. Dessa forma, possibilitando implementações
concretas desses DAO’s de maneiras distintas. Por exemplo, para um DAO que
possui métodos referentes ao domínio de bens patrimoniais, criou-se a classe
concreta BemImpl. Por sua vez, esta classe implementa a interface BemDAO, que
possui a definição dos métodos que ela deve implementar. Nesta abordagem, a
interface BemDAO deve herdar da interface GenericDAO e a classe BemImpl deve
herdar da classe GenericSipacDAO.
Nas implementações mais atuais, não é necessário mais criar os DAOs do SIPAC
utilizando interfaces abstratas. A criação passa a ser semelhante a dos projetos
SIGPRH e SIGAA como visto mais adiante.
A instanciação de objetos DAO’s no SIPAC não é feita através do operador new.
Para isso é utilizado os padrões de projetos Factory Method e Abstract Factory. A
classe DAOFactory é uma fábrica de objetos DAO’s. Para isso, ela utiliza as
constantes definidas na classe ConstantesDAO que indicam qual o tipo de
implementação que os DAO’s devem ter.
BemDAO bemDAO1 = (BemDAO) DAOFactory.getInstance().getDAO(ConstantesDAO.BemImpl, req);
try{
Collection<Bem> bens = bemDAO1.findByEmpenho(234);
}finally{
bemDAO1.close();}
Nos casos de uso desenvolvidos no SIPAC com Struts, os DAO’s podem ser criados
como na Listagem 6.4 ou como ilustrado na Listagem 6.3. O método getDAO,
invocado em uma Action, é herdado da classe AbstractAction e encapsula a criação
do DAO através da classe DAOFactory.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
12
BemDAO bemDAO1 = (BemDAO) getDAO(ConstantesDAO.BemImpl, req);
try{
Collection<Bem> bens = bemDAO1.findByEmpenho(234);
}finally{
bemDAO1.close();
}
Os sistemas SIGPRH e SIGAA começaram a ser desenvolvidos após o SIPAC.
Neles, a abordagem de utilização de interfaces genéricas e dos padrões de projetos
Factory Method e Abstract Factory foi abandonada. Nestes casos, faz-se necessário
apenas a criação de uma classe concreta que representa o DAO herdando a classe
GenericSigrhDAO ou GenericSigaaDAO. Atualmente, os novos DAOs do SIPAC não
são mais criados com esta abordagem e sim com a abordagem aplicada ao SIGPRH
e SIGAA, como apresentando mais adiante.
Todos os casos de uso do SIGRH, alguns do SIPAC e a maioria do SIGAA são
desenvolvidos através da tecnologia JSF.
A Listagem 6.5 apresenta a criação de DAO’s em casos de uso desenvolvidos em
JSF em quaisquer dos sistemas. A criação ilustrada é feita dentro de
ManagedBeans. O método getDAO é definido e implementado na classe
AbstractController. Dentro dele o DAO que corresponde à classe passada como
argumento é instanciado através do operador new.
TurmaDAO turmaDAO = (TurmaDAO) getDAO(TurmaDAO.class);
Padrão OpenSessionView
Durante a exibição das views do sistema, muitas vezes, diversas entidades do
modelo são renderizadas, e essas podem ter sido carregas pelo Hibernate. Se essas
entidades possuem relacionamentos LazyType.LAZY que também serão exibidos,
precisa-se que a sessão com a base de dados esteja aberta no momento da
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
13
renderização da view. Caso contrário uma exceção do tipo será disparada. Um
solução seria mapear os org.hibernate,LazyInitializationException relacionamentos
com LazyType.EAGER ou então, antes de enviar os dados da entidade para view,
realizar a consulta dos dados definidos lazy.
Outra solução seria a utilização do padrão Open Session in View, que faz com que a
sessão com a base de dados fique aberta através de um filtro, interceptador ou
algum outro mecanismo. Dessa forma, a sessão ficaria aberta durante toda a
requisição (request) e sua finalização seria feita através do filtro, por exemplo.
O padrão OpenSessionView é utilizado na arquitetura dos sistemas. O
funcionamento do padrão é implementado através dos métodos getDAO dos
controladores br.ufrn.arq.web.jsf. AbstractController e
br.ufrn.arq.web.struts.AbstractAction, utilizados para implementação de casos de uso
em JSF e Struts, respectivamente. Em ambas situações, o método getDAO invoca
um outro método getCurrentSession, ilustrado na Listagem 6.6, onde caso a sessão
com o Hibernate ainda não estiver aberta, ela é criada, caso contrário, a sessão já
aberta é retornada.
No momento da criação da sessão, o atributo Database.SESSION_ATRIBUTE é
colocado na requisição HTTP.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
14
public Session getCurrentSession(HttpServletRequest req) {
if (req != null) {
//Indicará se a sessão está aberta
Session current = (Session) req.getAttribute(Database.SESSION_ATRIBUTE);
if (current == null || !current.isOpen()) {
Integer sistema = getSistema(req);
if (sistema == Sistema.SIPAC) {
current = DAOFactory.getInstance().getSfSipac().openSession();
} else if (sistema == Sistema.SIGAA) {
current = DAOFactory.getInstance().getSfSigaa().openSession();
}
//Atributo que auxiliará o uso do padrão open session in view
req.setAttribute(Database.SESSION_ATRIBUTE, current);
}
return current;
} else {
return null;
}
}
O controle do fechamento automático da sessão com o banco de dados é feito
através de um Filtro (javax.servlet.Filter), chamado br.ufrn.arq.web.ViewFilter, que
tem a função de interceptar qualquer requisição HTTP realizada pelo cliente.
O último trecho de código do ViewFilter é justamente o fechamento da sessão com o
Hibernate, conforme visto na Listagem 6.7, liberando o programador desta tarefa.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
15
http://www.google.com/search?hl=en&q=allinurl:docs.oracle.com+javase+docs+api+integer
http://www.google.com/search?hl=en&q=allinurl:docs.oracle.com+javase+docs+api+integer
Session session = (Session) req.getAttribute(Database.SESSION_ATRIBUTE);
if (session != null && session.isOpen()) {
session.clear();
session.close();
}
Listagem 6.7 - Fechamento da Sessão com Hibernate no ViewFilter
Realizando o Mapeamento Objeto Relacional
O mapeamento objeto relacional entre entidades dos sistemas e as tabelas do banco
de dados é feito com o framework Hibernate. Há duas formas de realizar este
mapeamento, utilizando arquivos XML ou utilizando anotações. No SIPAC, a maior
parte do mapeamento é feita utilizando arquivos XML, pois quando começou a ser
desenvolvido a abordagem de mapeamento por anotações de classes ainda não
existia. As entidades mais atuais já são mapeadas utilizando anotações. No SIGRH
e SIGAA todo o mapeamento das entidades é feito utilizando anotações.
A Listagem 6.8 e a Listagem 6.9 apresentam exemplos de mapeamentos de classes
de domínio, respectivamente, através de arquivo XML e através de anotações.
É importante ressaltar que comentários devem ser inseridos para a definição das
classes e dos atributos contidos nelas. No momento da criação da tabela do banco
de dados que representa a classe, deve-se inserir os mesmos comentários para a
tabela e para as suas colunas.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
16
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="br.ufrn.sipac.compras.licitacao.dominio.CartaConvite"
table="CARTA_CONVITE" dynamic-update="false"
dynamic-insert="false" schema="compras">
<id name="id" column="ID_CARTA_CONVITE" type="int" unsaved-value="0">
<generator class="sequence">
<param name="sequence">carta_seq</param>
</generator>
</id>
<property name="dataCadastro" type="java.util.Date" update="true"
insert="true" access="property" column="DATA" not-null="true"/>
<many-to-one fetch="join" name="fornecedor"
class="br.ufrn.sipac.cadastro.dominio.Pessoa" cascade="none"
outer-join="true" update="true" insert="true" access="property"
column="ID_FORNECEDOR"/>
<!-- Demais mapeamentos... -->
</class>
</hibernate-mapping>
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
17
package br.ufrn.sipac.contratos.dominio;
/* Imports necessários */
/**
* Classe de domínio que representa uma ocorrência lançada para o contrato. Um
conjunto de ocorrências compõe o livro de ocorrências do contrato
*
* @author Raphaela Galhardo
*/
@Entity
@Table(name = "OCORRENCIA_CONTRATO", schema = "contratos")
public class OcorrenciaContrato extendsAbstractMovimento {
/** Identificador */
@Id
@GeneratedValue( strategy = GenerationType.SEQUENCE,generator = "SEQ_OCORRENCIA")
@SequenceGenerator( name = "SEQ_OCORRENCIA", allocationSize = 1,
sequenceName = "contratos.ocorrencia_contrato_seq")
@Column(name = "id_ocorrencia_contrato")
private int id;
/** Data da ocorrência */
@Temporal(TemporalType.DATE)
private Date data;
/** Descrição da Ocorrência */
private String descricao;
/** Contrato associado à ocorrência */
@ManyToOne
@JoinColumn(name = "id_contrato", nullable = false)
private Contrato contrato;
/** Usuario que lanca a ocorrencia */
@ManyToOne
@JoinColumn(name = "id_usuario", nullable = false)
private Usuario usuario;
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
18
http://www.google.com/search?hl=en&q=allinurl:docs.oracle.com+javase+docs+api+entity
http://www.google.com/search?hl=en&q=allinurl:docs.oracle.com+javase+docs+api+date
http://www.google.com/search?hl=en&q=allinurl:docs.oracle.com+javase+docs+api+date
http://www.google.com/search?hl=en&q=allinurl:docs.oracle.com+javase+docs+api+string
http://www.google.com/search?hl=en&q=allinurl:docs.oracle.com+javase+docs+api+string
/** Nota fiscal associada à ocorrencia. Quando tiver */
@ManyToOne
@JoinColumn(name = "id_nota_fiscal")
private NotaFiscal notaFiscal;
/* Demais atributos e seus respectivos mapeamentos */
/* Métodos getters e setters */
}
Anotações Auxiliares para o Mapeamento Objeto-Relacional
Alguns campos de entidades são utilizados mais para auditoria ou para
ativação/inativação de entidades. Eles podem ser populados automaticamente pela
arquitetura se possuirem um determinado nome padrão ou se possuírem uma
anotação definida na arquitetura. Tais informações podem ser vistas na tabela
abaixo:
Nome padrão
do campo Anotação Descrição
criadoPor @CriadoPor
Utilizado em campos da classe de domínio do tipo
UsuarioGeral ou subclasses. No cadastro das entidades, o
campo será populado automaticamente com o usuário que
está realizando o cadastro.
criadoEm @CriadoEm
Utilizado em campos da classe de domínio do tipo
java.util.Date ou RegistroEntrada. No cadastro das entidades,
o campo será populado automaticamente com a data de
cadastro ou com o registro de entrada do usuário que está
realizando o cadastro.
atualizadoPor @AtualizadoPor
Utilizado em campos da classe de domínio do tipo
UsuarioGeral ou subclasses. Na atualização das entidades, o
campo será populado automaticamente com o usuário que
está realizando a atualização.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
19
atualizadoEm @AtualizadoEm
Utilizado em campos da classe de domínio do tipo
java.util.Date ou RegistroEntrada. Na atualização das
entidades, o campo será populado automaticamente com a
data da atualização ou com o registro de entrada do usuário
que está realizando a atualização.
ativo @CampoAtivo
Utilizado em campos do tipo boolean. No cadastro das
entidades, os campos com essa anotação são populados
automaticamente com true.
6.6 Mecanismos para Facilitar Consultas ao Banco de Dados
Em sua grande maioria, as consultas ao banco de dados são feitas utilizando os
recursos disponibilizados pelo Hibernate (Criteria e HQL). Em algumas situações, é
necessária a utilização de consultas com JDBC diretamente, principalmente quando
o resultado tem que ser feita da forma mais rápida e eficiente possível.
Considere o exemplo mostrado na Listagem 6.10, onde é realizada uma consulta
com JDBC. Dessa forma, todo o gerenciamento de conexão, de Statements,
ResultSets, tratamento de transações, etc. deve ser feito pelo programador.
int count = 0;
Connection con = getConnection();
PreparedStatement st = null;
try{
st = con.preparedStatement("select count(*) from cliente");
ResultSet rs = st.executeQuery();
if (rs.next()){
count = rs.getInt(1);
}
}catch(SQLException e){
//Tratamento do erro
}finally{
try{ if (st != null) st.close();} catch(SQLException e){//Tratamento}
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
20
http://www.google.com/search?hl=en&q=allinurl:docs.oracle.com+javase+docs+api+connection
http://www.google.com/search?hl=en&q=allinurl:docs.oracle.com+javase+docs+api+connection
http://www.google.com/search?hl=en&q=allinurl:docs.oracle.com+javase+docs+api+preparedstatement
http://www.google.com/search?hl=en&q=allinurl:docs.oracle.com+javase+docs+api+preparedstatement
http://www.google.com/search?hl=en&q=allinurl:docs.oracle.com+javase+docs+api+resultset
http://www.google.com/search?hl=en&q=allinurl:docs.oracle.com+javase+docs+api+sqlexception
http://www.google.com/search?hl=en&q=allinurl:docs.oracle.com+javase+docs+api+sqlexception
try{ if (con != null) con.close();}catch(SQLException e){//Tratamento}
}
A utilização do Spring na arquitetura disponibiliza um template para acesso ao banco
de dados com JDBC de forma mais simplificada, o JDBCTemplate. Existe a classe
br.ufrn.arq.dao.JdbcTemplate, disponível na arquitetura, que herda a classe
org.springframework.jdbc.core.JdbcTemplate do Spring.
Dessa forma, o programador necessita se preocupar apenas com a consulta SQL
gerada, com a definição do tipo de retorno e de seus parâmetros. Por exemplo, na
Listagem 6.11 há uma simplificação da consulta presente na Listagem 6.10.
JdbcTemplate jt = new JdbcTemplate(getDataSource());
int count = jt.queryForInt("select count(*) from cliente");
Listagem 6.11 - Consulta com JdbcTemplate()Spring
Vários tipos de retornos podem ser utilizados com JDBCTemplate. Entre eles:
● query: resultado da consulta como um Object.
● queryForInt: resultado da consulta como um número inteiro.
● queryForLong: resultado da consulta como um número do tipo long.
● queryForDouble: resultado da consulta como um número do tipo double.
● queryForMap: resultado da consulta como um mapa, representando uma
única linha retornada da tabela. A chave é o nome da coluna e o valor da
chave o conteúdo presente na coluna correspondente.
● queryForList: resultado da consulta como uma lista de mapas, representando
mais de uma linha retornada da tabela. Cada elemento da lista é uma linha da
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
21
http://www.google.com/search?hl=en&q=allinurl:docs.oracle.com+javase+docs+api+sqlexception
tabela em forma de mapa. A chave é o nome da coluna e o valor da chave o
conteúdo presente na coluna correspondente.
Exemplos de uso do JDBCTemplate
1. Realizar uma consulta que retorna apenas um número.
Utilize o método queryForInt(). Ele recebe como parâmetros uma String e um array
de Object com os parâmetros da consulta (opcional).
Exemplo na Listagem 6.12:
public int getNumeroUsuarios(Unidade u) {
return getJdbcTemplate().queryForInt(
"select count(*) from usuario where id_unidade=?", new Object[]{u.getId()});
}
Obs.: Existe ainda o método queryForLong(), para o caso de o resultado não caber
em um int.
2. Realizar uma consulta que retorna um único objeto.
Utilize o método queryForObject(). Ele recebe dois ou três parâmetros. O primeiro é
uma String com a consulta SQL, o segundo (opcional) é um array de Objects com os
parâmetros e o terceiro é um RowMapper, uma interface que mapeia um ResultSet
em um objeto.
Exemplo na Listagem 6.13:
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
22
http://www.google.com/search?hl=en&q=allinurl:docs.oracle.com+javase+docs+api+objecthttp://www.google.com/search?hl=en&q=allinurl:docs.oracle.com+javase+docs+api+object
public Discente findByMatricula(long matricula) {
return (Discente) getJdbcTemplate().queryForObject(
"select * from discente where matricula = ?", new Object[]{matricula},
new RowMapper() {
public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
Discente d = new Discente();
d.setId(rs.getInt("id_discente"));
d.setAnoIngresso(rs.getInt("ano_ingresso"));
d.setPeriodoIngresso(rs.getInt("periodo_ingresso"));
//... setar demais atributos
return d;
}
});
}
3. Realizar uma consulta que retorna uma lista de objetos.
Utilize o método query(), que é muito parecido com o queryForObject().
Exemplo na Listagem 6.14:
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
23
http://www.google.com/search?hl=en&q=allinurl:docs.oracle.com+javase+docs+api+object
http://www.google.com/search?hl=en&q=allinurl:docs.oracle.com+javase+docs+api+object
http://www.google.com/search?hl=en&q=allinurl:docs.oracle.com+javase+docs+api+rowmapper
http://www.google.com/search?hl=en&q=allinurl:docs.oracle.com+javase+docs+api+rowmapper
http://www.google.com/search?hl=en&q=allinurl:docs.oracle.com+javase+docs+api+object
http://www.google.com/search?hl=en&q=allinurl:docs.oracle.com+javase+docs+api+object
http://www.google.com/search?hl=en&q=allinurl:docs.oracle.com+javase+docs+api+resultset
http://www.google.com/search?hl=en&q=allinurl:docs.oracle.com+javase+docs+api+sqlexception
http://www.google.com/search?hl=en&q=allinurl:docs.oracle.com+javase+docs+api+sqlexception
public List<Discente> findByCurso(Curso curso) {
return (Discente) getJdbcTemplate().query(
"select * from discente where id_curso = ?", new Object[]{curso.getId()},
new RowMapper() {
public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
Discente d = new Discente();
d.setId(rs.getInt("id_discente"));
d.setAnoIngresso(rs.getInt("ano_ingresso"));
d.setPeriodoIngresso(rs.getInt("periodo_ingresso"));
//... setar demais atributos
return d;
}
});
}
4. Realizar insert, update, delete.
Utilizar o método update(). Exemplo na Listagem 6.15:
getJdbcTemplate().update("insert into teste (nome, valor) values (?, ?)", new Object[] { "Fulano",
1.99 });
getJdbcTemplate().update("update teste set nome=? where id=?", new Object[] { "Beltrano", 3 });
getJdbcTemplate().update("delete from teste where id=?", new Object[] { 5 });
5. Realizar Batch (Lote) Update.
Utilizar o método batchUpdate(). Existem duas formas de se utilizá-lo. A primeira é
passando um array de Strings de consultas SQL e a segunda passando um SQL e
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
24
http://www.google.com/search?hl=en&q=allinurl:docs.oracle.com+javase+docs+api+object
http://www.google.com/search?hl=en&q=allinurl:docs.oracle.com+javase+docs+api+object
http://www.google.com/search?hl=en&q=allinurl:docs.oracle.com+javase+docs+api+rowmapper
http://www.google.com/search?hl=en&q=allinurl:docs.oracle.com+javase+docs+api+rowmapper
http://www.google.com/search?hl=en&q=allinurl:docs.oracle.com+javase+docs+api+object
http://www.google.com/search?hl=en&q=allinurl:docs.oracle.com+javase+docs+api+object
http://www.google.com/search?hl=en&q=allinurl:docs.oracle.com+javase+docs+api+resultset
http://www.google.com/search?hl=en&q=allinurl:docs.oracle.com+javase+docs+api+sqlexception
http://www.google.com/search?hl=en&q=allinurl:docs.oracle.com+javase+docs+api+sqlexception
http://www.google.com/search?hl=en&q=allinurl:docs.oracle.com+javase+docs+api+object
http://www.google.com/search?hl=en&q=allinurl:docs.oracle.com+javase+docs+api+object
http://www.google.com/search?hl=en&q=allinurl:docs.oracle.com+javase+docs+api+object
http://www.google.com/search?hl=en&q=allinurl:docs.oracle.com+javase+docs+api+object
http://www.google.com/search?hl=en&q=allinurl:docs.oracle.com+javase+docs+api+object
http://www.google.com/search?hl=en&q=allinurl:docs.oracle.com+javase+docs+api+object
um BatchPreparedStatementSetter, onde os parâmetros de cada update serão
setados.
Camada de Domínio/Negócio
A camada de domínio/negócio fornece um conjunto de classes e interfaces que
provê a padronização e infra-estrutura para efetivação das operações de negócio.
As classes de domínio modelam o contexto do negócio. Por exemplo, a Figura 7.1
ilustra um conjunto de classes de domínio que representam parte do contexto do
subsistema de Compras/Licitações do sistema SIPAC. Cada classe é formada por
um conjunto de atributos e pode se relacionar com outras classes.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
25
Existe na arquitetura duas interfaces que devem ser implementadas pelas classes
de domínios em algumas situações: br.ufrn.arq.dominio.PersistDB e
br.ufrn.arq.dominio.Validatable.
A interface PersistDB deve ser implementada por todas as classes de domínios que
terão objetos persistidos, através da camada de objeto relacional. O seu conteúdo
está presente na Listagem 7.1. Observa-se a existência de dois métodos que devem
ser obrigatoriamente implementados pelas classes que implementam esta interface.
Estes métodos representam os métodos que definem e recuperam o valor da chave
primária (em geral denominado id) de uma entidade persistente.
public interface PersistDB extends Serializable {
public int getId();
public void setId(int id);
}
A interface Validatable deve ser implementada por todas as classes de domínios que
usufruirão de mecanismos disponibilizados pela arquitetura para a realização de
operações de CRUDs. O seu conteúdo está presente na Listagem 7.2. O método
definido na interface deve ser implementado pelas classes que implementam esta
interface. Ele será utilizado para a validação de preenchimento obrigatório de dados
de um formulário (Mais detalhes na seção 8.2.2).
public interface Validatable extends PersistDB {
public ListaMensagens validate();
}
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
26
A persistência das informações modeladas pelas classes de domínio é feita através
de classes denominadas processadores que são invocadas através de um
componente EJB disponível na arquitetura.
A arquitetura foi modelada usando o padrão de projeto EJB Command. Através
desta padronização, todo caso de uso possui um código de comando que é
executado por um processador. Os processadores são as classes responsáveis pela
implementação da lógica de negócio. Não é obrigatório que toda e qualquer lógica
de negócio esteja contida em processadores, pois, em várias situações existem
lógicas de negócio acessórias que fazem parte de uma ou várias operações de
negócio. Nestes casos, a arquitetura recomenda a utilização de classes auxiliares
(Helper Classes ou Util Classes) para a implementação dessas lógicas de negócio
auxiliares.
Todos os processadores de comandos devem herdar a classe
br.ufrn.arq.negocio.AbstractProcessador. Esta, por sua vez, implementa a interface
br.ufrn.arq.negocio.ProcessadorComando , que define os métodos execute (onde o
código de persistência deve aparecer) e validate (onde o código de validação de
permissões e regras de negócio é definido), que devem ser implementados pelos
processadores dos sistemas.
A classe br.ufrn.arq.negocio.ProcessadorCadastro que pode ser utilizado para a
implementação de operações simples, que possuem apenas as operações básicas
de CRUD. Nela, é definido um conjunto de métodos suficientes para a
implementaçãode casos de usos definidos por CRUDs. Por exemplo, para a
criação, alteração, remoção de uma linha de alguma tabela representada por um
objeto persistente na aplicação.
Para casos de usos que não representam simplesmente CRUDs, ou seja, que
possuem um conjunto de regras de negócios, uma ou mais operações relacionadas
à persistência, é necessária a criação de um processador específico. Por exemplo,
no SIPAC, o processador ProcessadorOcorrenciaContrato; no SIGRH, o
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
27
processador ProcessadorFrequencia e no SIGAA, o processadorEstruturaCurricular ;
Todos esses novos processadores devem herdar de ProcessadorCadastro.
Os movimentos são elementos que conduzem os dados de negócio para serem
processados pelas classes processadoras do sistema. Classes que são movimentos
devem herdar da classe br.ufrn.arq.negocio.AbstractMovimento que implementa a
interface br.ufrn.arq.negocio.Movimento , e possui métodos úteis e comuns aos
diversos movimentos dos sistemas. O final de um caso de uso que provoca
alterações na base de dados é a chamada de um processador que executará a
lógica de negócio. Dessa forma, o conteúdo visto dentro deste processador chega
em forma de um movimento, que é montado ao longo da execução do caso de uso.
A classe br.ufrn.arq.dominio.MovimentoCadastro representa um movimento padrão a
diversos casos de uso, onde as informações utilizadas pelo processador na
execução da lógica de negócio podem ser resumidas em um único objeto
(representado pelo atributo objMovimentado) e/ou em uma coleção de objetos
(representada pelo atributo colObjMovimentado). Caso haja necessidade de se
enviar outros tipos de informações, pode-se criar classes movimentos específicas
para o caso de uso, como por exemplo, as classes MovimentoAcademico do SIGAA
e MovimentoAusencia do SIGRH, que devem herdar de MovimentoCadastro.
Através de um objeto MovimentoCadastro define-se o processador que será
invocado para a persistência dos dados. A definição é feita através do valor do
atributo codMovimento, que define qual processador deve ser executado. Para os
casos de uso, comandos que ficam agrupados em classes presentes. Para o projeto
do SIGRH, SigrhListaComando; em cada projeto são definidos, como visto na Figura
7.4 para o projeto do SIPAC, SipacListaComando; e para o projeto do SIGAA,
SigaaListaComando.
Através do EJB Command, os clientes (MovimentoCadastro) não sabem que classe
de processador elas irão ativar. Conhecem apenas o comando. Para suportar a
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
28
localização e ativação dos comandos, a arquitetura implementa uma fachada de
ativação. Os elementos da fachada são mostrados na Figura 7.5.
A classe br.ufrn.arq.negocio.SessionAdapter é uma implementação do design
pattern Class Adapter que adapta a interface do EJB a Object, permitindo que o
br.ufrn.arq.negocio.ArqFacadeBean (implementação do Session Façade) não seja
obrigado a implementar os métodos requeridos na interface Session Bean. A classe
br.ufrn.arq.negocio.FacadeDelegate implementa o padrão de projeto Bussiness
Delegate e é usada para ativar o Session Façade. A classe
br.ufrn.arq.negocio.MovimentoLocator, que implementa os padrões Service Locator
e Singleton, é a responsável por localizar os processadores de comando.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
29
A seqüência para ativação dos comandos basicamente é a seguinte: o primeiro
passo antes da efetivação de um comando é seu desbloqueio. Todo comando,
quando executado pelo usuário, é bloqueado até que um desbloqueio explícito seja
gerado. Este mecanismo serve para evitar que envios sucessivos do usuário (como
pressionar a tecla F5 no browser) sejam processados desnecessariamente,
ocasionando replicação de dados. O comando prepareMovimento(), que recebe o
código do movimento, efetua o desbloqueio.
Um objeto FacadeDelegate recebe as solicitações de execução vindas da camada
WEB e encaminha a chamada ao ArqFacadeBean, através do método execute(). O
ArqFacadeBean então solicita ao MovimentoLocator qual o processador responsável
pela operação. A localização é feita através do método getCodMovimento() no
movimento que está sendo passado no argumento. Quando o processador for
localizado, ele é chamado e o movimento é então processado e retornado ao cliente.
No processador, algumas validações de regras de negócio podem ser feitas dentro
do método validate().
Camada de Apresentação
A camada de apresentação é utilizada para exibir informações aos usuários que
utilizam os sistemas. Essas informações podem ser apresentadas, por exemplo, em
janelas e páginas HTML.
Na camada de apresentação, utiliza-se o padrão de projeto MVC, que descreve
como os componentes da camada de apresentação devem interagir. Através do uso
deste padrão, três tipos de componentes são definidos:
● Modelo: objetos da camada de domínio.
● Visão: usado para exibir o estado atual do modelo.
● Controle: recebe a entrada do usuário, manipula o modelo e provoca uma
atualização de visão.
Os componentes de visão e controle fazem parte da camada de apresentação.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
30
Componentes de Visão
JSP
JavaServer Pages (JSP) é uma tecnologia baseada em servlet usada na camada
WEB para apresentar conteúdo dinâmico e estático. Ela é baseada em texto e
contém, em sua maioria, modelo de texto em HTML misturado com tags que
especificam conteúdo dinâmico.
JavaScript
JavaScript é uma linguagem script desenvolvida inicialmente pela Netscape e
utilizada, entre outras aplicações, em milhões de páginas web e servidores de
aplicação. É uma linguagem dinâmica, fracamente tipada, baseada em protótipos e
com suporte a 'first-class functions'. Planejada para ter sua sintaxe parecida a Java e
C++, é facilmente assimilada por desenvolvedores que já conhece alguma delas.
No contexto das aplicações web, JavaScript torna-se bastante importante por
possibilitar a manipulação de elementos das páginas de forma a modificá-la ou
adicionar comportamentos dinâmicos e tratamento de eventos. Isto possibilita a
definição de operações que podem trabalhar diretamente no lado do cliente, sem a
necessidade de comunicação com o servidor para atualização de valores ou trechos
da página.
Em nossa arquitetura existem disponíveis várias bibliotecas e códigos
compartilhados que podem ser aplicados na implementação de operações dos
sistemas.
CSS
Cascading Style Sheets, ou simplesmente CSS, é uma linguagem de estilo utilizada
para definir a HTML ou XML. Seu principal apresentação de documentos escritos em
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
31
uma linguagem de marcação, como benefício é prover a separação entre o formato e
o conteúdo de um documento.
Para o desenvolvimento dos módulos dos sistemas institucionais, deve-se seguir um
conjunto de padronizações definidas pelo seu estilo CSS.
Compactação de Recursos Web(Javascripts e CSS)
Os recursos WEB, tais como Javascripts e CSS, podem ter um grande impacto na
performance de uma aplicação web. Dessa forma, foram adotadas algumas medidas
para melhorar o empacotamento de compactação destes nos sistemas
desenvolvidos.
Inicialmente, uma solução que empacotava vários arquivos Javascript em um único
foi adotada, já retirando espaços e comentários. Esta abordagem melhorou o acesso
às páginas ao reduzir o overhead de requisições HTTP para a busca de vários
arquivos. Então surgiram os arquivos build/ufrn.js e build/sigaa.js. Entretanto, depois
de algum tempo o utilitário deixou de funcionare passou-se a ter que realizar a
manutenção neste único e quase ilegível arquivo.
Outra melhoria foi o ScriptCompressorServlet, que compactava arquivos Javascript
quando carregados através dele. Esta Servlet ainda é usada hoje em vários locais e
proporciona uma redução no tamanho dos arquivos Javascripts disponibilizados.
Com o propósito de simplificar e unificar a forma de gerenciamento destes recursos,
essas duas abordagens foram substituidas por uma outra, utilizando uma biblioteca
Java chamada Jawr (https://jawr.dev.java.net/). Esta biblioteca auxilia na construção
de pacotes de recursos, sejam eles Javascript ou css, utilizando descritores em
arquivos de propriedades. Adicionalmente ela possui filtros pré-definidos que
compactam os arquivos com gzip, compactação esta suportada por todos os
navegadores modernos.
Descrição do Funcionamento
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
32
https://jawr.dev.java.net/
As configurações necessárias para os sistemas (ARQ, SIGAA, SIPAC e SIGRH) já
foram realizadas para todos os sistemas: *Adicionar a biblioteca ao classpath;
*Configurar o arquivo web.xml; *Importar o TLD no cabeçalho; *Definir o arquivo de
propriedades.
O arquivo de propriedade está, por padrão, no pacote br.ufrn._sistema_.arq.web,
chamando-se jawr.properties. Neste arquivo de propriedades foram definidos os
vários 'bundles' com os arquivos css e javascript, agrupados por contexto. Sejam
eles para uso local do sistema ou, no caso de ARQ, para serem usados por todos os
sistemas. Mais informações sobre o formado dos descritores podem ser vistos em
https://jawr.dev.java.net/docs/custom_bundles.html. Assim, foi definido para cada
sistema um bundle específico. Temos então um sigaa_base.js/css, um
sipac_base.js/css e um sigrh_base.js/css, contendo todos os arquivos necessários
para importação no cabeçalho principal de cada sistema. Para o caso de scripts
locais, basta utilizar as tags <jwr:style/> para importar CSS e <jwr:script/> para
importar javascripts. No caso de scripts ou estilos que estão em ARQ e precisam ser
acessados de outro contexto web (por exemplo, do SIGAA, SIPAC, etc.) é
necessário fazer as importações, utilizando uma função javascript especial, como
presente na Listagem 10.
<script type="text/javascript">
JAWR.loader.style('/bundles/css/sigaa_base.css');
JAWR.loader.style('/css/ufrn_print.css', 'print');
JAWR.loader.script('/bundles/js/sigaa_base.js');
</script>
Isto se faz necessário pela forma como o JAWR define a URL dos recursos em
tempo de inicialização da aplicação.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
33
https://jawr.dev.java.net/docs/custom_bundles.html
https://jawr.dev.java.net/docs/custom_bundles.html
Na forma como foi configurado, o JAWR foi está funcionando de modo compatível às
importações já existentes nas páginas, com a nova forma substituindo aos poucos a
anterior.
Componentes de Controle
A camada WEB da arquitetura tem a função de abstrair e/ou estender algumas
funcionalidades dos framework Struts e JSF, auxiliando o desenvolvimento dos
casos de uso.
Arquitetura com Struts
De uma forma geral, a arquitetura contribui na camada WEB com Struts nas
seguintes funcionalidades:
● Abstração/Extensão do ActionForm padrão do Struts;
● Abstração/Extensão da Action do Struts;
● Controlador Personalizado;
● Implementação de Tag-Libraries Personalizadas.
A arquitetura com struts para o desenvolvimento dos sistemas institucionais.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
34
br.ufrn.arq.web.struts.AbstractAction
Na Figura 8.1, a classe br.ufrn.arq.web.struts.AbstractAction é abstrata e herda da
classe org.apache.struts.action.DispatchAction do Struts. A classe DispatchAction
também é abstrata e é filha da classe org.apache.struts.action.Action do Struts.
Dessa forma, todas as classes desenvolvidas no sistema com função de uma action
do Struts devem, obrigatoriamente, herdar a classe AbstractAction.
Os principais métodos da classe abstrata br.ufrn.arq.web.struts.AbstractAction são:
● public UsuarioGeral getUsuarioLogado(HttpServletRequest req) throws
ArqException: Retorna o usuário autenticado no sistema no momento. As
informações do usuário são armazenadas em um atributo (usuario) da sessão
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
35
WEB (javax.servlet.http.HttpSession), através de um objeto
br.ufrn.comum.UsuarioGeral.
● public Integer getSistema(HttpServletRequest req): Retorna um identificador
inteiro que representa o sistema em que o usuário está navegando: SIPAC,
SIGAA, SIGRH. Na classe br.ufrn.comum.dominio.Sistema encontram-se
constantes que representam os subsistemas.
● public Object execute(Movimento mov, HttpServletRequest req) throws
NegocioException, ArqException, RemoteException: Recebe um objeto
br.arq.dominio.Movimento e permite a comunicação com o EJB, representado
pelo processador, onde é executada a lógica de negócio. O processador é
selecionado de acordo com um código de movimento, obtido através do
método de assinatura br.arq.dominio.Comando getCodMovimento()
implementado em classes que implementam a interface Movimento.
● public void prepareMovimento(int codMovimento, HttpServletRequest req)
throws ArqException, RemoteException, NegocioException: por padrão, a
chamada a um processador só pode ser feita uma única vez. Após a sua
primeira chamada, para que ele possa vir a ser invocado novamente, deve-se
liberar esta chamada. Este método faz exatamente isso, habilita um
processador de ter o seu código executado mais uma vez. O processador
habilitado é aquele que corresponde ao código de movimento (identificador)
passado como argumento. O dado da requisição web é utilizado para a
verificação de informações referente ao usuário logado presente na sessão
web. Após a execução do código presente em um processador, ele é
novamente bloqueado.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
36
● public void prepareMovimento(Comando comando, HttpServletRequest req)
throws ArqException, RemoteException, NegocioException: este método faz
exatamente o mesmo que o método descrito anteriormente. A diferença é que
ao invés de receber o identificador do comando, ele recebe o objeto
Comando.
● public GenericDAO getGenericDAO(HttpServletRequest req) throws
ArqException: método que retorna um objeto do tipo GenericDAO utilizado
para realizar a comunicação com o banco de dados. Mais detalhes sobre
DAO na sessão Camada de Mapeamento.
● public GenericDAO getDAO(String constanteDAO, HttpServletRequest req)
throws ArqException: método que retorna um objeto do tipo GenericDAO
utilizado para realizar a comunicação com o banco de dados. A instância da
classe retornada corresponde à identificada pela String constanteDAO. Usado
no SIPAC. Mais detalhes na sessão Camada de Mapeamento.
● public <T extends GenericDAO> T getDAO(Class<T> daoClass,
HttpServletRequest req) throws ArqException: método que retorna um objeto
do tipo GenericDAO utilizado para realizar a comunicação com o banco de
dados. A instância da classe retornada corresponde à identificada pelo
atributo daoClass. Mais detalhes na sessão Camada de Mapeamento.
● public void checkRole(int papel, HttpServletRequest req) throws
SegurancaException, ArqException: método para a verificação se o usuário
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
37
logado possui o papel passado como argumento. Utilizado para verificação de
permissões.
● public void checkRole(int[] papeis,HttpServletRequest req) throws
SegurancaException, ArqException: método para a verificação se o usuário
logado possui o conjunto de papéis passados como argumento. Utilizado para
verificação de permissões.
● public void checkRoleSipac(HttpServletRequest req) throws
SegurancaException, ArqException: método para a verificação se o usuário
logado possui algum papel dos subsistemas do SIPAC. Utilizado para
verificação de permissões.
SigaaAbstractAction
Action que abstrai métodos utilizados apenas no desenvolvimento de operações no
sistema acadêmico, SIGAA.
Action que funciona com Layer Supertype
( http://martinfowler.com/eaaCatalog/layerSupertype.html) para as demais Actions do
SIGAA. Estende AbstractAction e possui um conjunto de métodos que auxiliam a
criação de casos de uso no SIGAA. Os métodos presentes nessa classe são:
● getGenericDAO(HttpServletRequest req): Retorna uma instância de
GenericDAO populada com uma Session do Hibernate configurada para
trabalhar com o Datasource do SIGAA.
● getDAO(Class<T> classe, HttpServletRequest req): Retorna uma instância do
DAO cuja classe foi passada como primeiro parâmetro. O DAO estará
populado com uma Session do Hibernate configurada para trabalhar com o
Datasource do SIGAA.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
38
http://martinfowler.com/eaaCatalog/layerSupertype.html
● getCurrentSession(HttpServletRequest req): Método utilizado pelo padrão
OpenSessionInView que retorna a Session do Hibernate que está
armazenada como atributo de request. Caso não exista o atributo em request
ou a session em request esteja fechada, uma nova session é aberta e
associada ao request.
● forceCloseConnection(HttpServletRequest req): Pega a session associada ao
request utilizando o método getCurrentSession() e a fecha.
● getSubSistemaCorrente(HttpServletRequest req): Retorna o subsistema que
está sendo utilizado atualmente pelo usuário. Essa informação é pega da
sessão do usuário.
● getUnidadeGestora(HttpServletRequest req): Retorna o identificador da
unidade Gestora Acadêmica do usuário logado.
● getNivelEnsino(HttpServletRequest req): Retorna o nível de ensino que está
atualmente associado ao usuário. Inicialmente, verifica qual o subsistema que
o usuário está utilizando e pega o nível de ensino desse subsistema. Caso o
nível de ensino não esteja definido para o subsistema, tentará pegar a
informação do nível da sessão. Se não encontrar, dispara uma ArqException
avisando que não foi possível descobrir o nível de ensino.
● flushOnlyErrors(HttpServletRequest req): Retorna true se existirem
mensagens de erro adicionadas à sessão, false caso contrário.
● executeWithoutClosingSession(HttpServletRequest req): Realiza as mesmas
operações que o método execute() definido em AbstractAction, mas não fecha
a Session do Hibernate antes.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
39
● getParametrosAcademicos(HttpServletRequest req): Retorna os parâmetros
acadêmicos armazenados em sessão. Os parâmetros deverão ter sido
carregados através do método carregaParametrosCalendarioAtual().
● getCalendarioVigente(HttpServletRequest req): Retorna o calendário
acadêmico armazenado em sessão. O calendário deverá ter sido carregado
através do método carregaParametrosCalendarioAtual().
● getAcessoMenu(HttpServletRequest req): retorna um objeto que que define o
nível de acesso a algumas operações no sistema.
● carregarParametrosCalendarioAtual(HttpServletRequest req): carrega em
sessão os parâmetros acadêmicos e o calendário atual, baseado na unidade
e nível de ensino do usuário.
● clearSessionWeb(HttpServletRequest req): Remove um conjunto de atributos
da sessão definidos no método clearSessionWEB em SigaaUtils.
AbstractCrudAction
Action que abstrai métodos utilizados no desenvolvimento de operações CRUD
simples no sistema acadêmico, SIGAA. Disponibiliza um conjunto de métodos
auxiliares às operações CRUD.
Classe filha de SigaaAbstractAction. Em conjunto com a classe SigaaForm e com a
possibilidade de utilizar “caracteres coringa” em mapeamentos do Struts, formam um
mecanismo de template que permite criar casos de uso de cadastro sem a
necessidade de implementá-los completamente.
Os mapeamentos existentes são:
/*/*/cadastro*
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
40
/*/cadastro*
Essas URLs são mapeadas para AbstractCrudAction e associadas ao form cujo
nome for o conteúdo do último asterisco seguido da palavra “Form”. Essas actions
possuem três forwards: form, listar e view. Esses forwards estão associados às JSPs
/WEB-INF/jsp/{1}/{2}/{3}/form.jsp, /WEB-INF/jsp/{1}/{2}/{3}/lista.jsp e /WEB-
INF/jsp/{1}/{2}/{3}/view.jsp, respectivamente, onde {1}, {2} e {3} são os conteúdos do
primeiro, segundo e terceiro asterisco. No caso do segundo mapeamento, os
forwards estão associados à /WEB-INF/jsp/{1}/{2}/form.jsp,
/WEB-INF/jsp/{1}/{2}/lista.jsp e /WEB-INF/jsp/{1}/{2}/view.jsp.
De acordo com essas informações, tomemos como exemplo a url
“/ensino/cadastroCurso.do”. Essa URL está associada a AbstractCrudAction e ao
form cursoForm. Além disso, os forwards estão associados às JSPs
/WEB-INF/jsp/ensino/Curso/form.jsp, /WEB-INF/jsp/ensino/Curso/lista.jsp e /WEB-
INF/jsp/ensino/Curso/view.jsp.
AbstractCrudAction possui todos os métodos necessários para realizar cadastros,
tais como:
● persist(ActionMapping mapping, ActionForm form, HttpServletRequest req,
HttpServletResponse res): Action para persistir os dados vindos de um
formulário no banco de dados. Se o identificador (id) for 0, a ação é de
cadastrar, se for diferente de 0 a ação é atualizar. Em caso de criação, o
usuário é redirecionado para o form, em caso de atualização o usuário é
redirecionado para a listagem.
● edit(ActionMapping mapping, ActionForm form, HttpServletRequest req,
HttpServletResponse res): Action para exibir o formulário em caso de
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
41
cadastro ou atualização. Atualização ocorre quando for passado por request
um parâmetro id diferente de 0.
● view(ActionMapping mapping, ActionForm form, HttpServletRequest req,
HttpServletResponse res): Action para exibir uma jsp com informações
detalhadas sobre o objeto que está sendo cadastrado.
● remove(ActionMapping mapping, ActionForm form, HttpServletRequest req,
HttpServletResponse res): Action para remoção. Se não existir um parâmetro
confirm em request, vai para edit com os campos desabilitados (apenas para
visualização). Se houver, apaga o objeto.
● list(ActionMapping mapping, ActionForm form, HttpServletRequest req,
HttpServletResponse res): Action para listar os objetos do cadastro e realizar
buscas utilizando os parâmetros de busca definidos em SigaaForm.
● cancel(ActionMapping mapping, ActionForm form, HttpServletRequest req,
HttpServletResponse res): Cancela a execução de um caso de uso,
redirecionando para a listagem, caso se esteja fazendo um cadastro,
atualização ou remoção; e redirecionando para a página do subsistema atual
do usuário, caso já se esteja na listagem.
Caso seja necessário modificar a forma como o cadastro é realizado, é possível
estender essa classe e sobrescrever alguns de seus métodos, mas será necessário
fazer o mapeamento no struts-config.xml para essa nova classe.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
42
br.ufrn.arq.web.struts.AbstractForm
A classe abstrata br.ufrn.arq.web.struts.AbstractForm é uma abstração/extensão da
classe org.apache.struts.actions.ActionForm do Struts, e deve ser herdada por todos
os Forms dos Sistemas.A classe abstrata AbstractForm possui atributos que auxiliam a população dos dados
que serão passados à action. Entre eles:
● acao: indica uma determinada ação realizada em determinado caso de uso.
Por exemplo, caso um form seja utilizado por mais de um caso de uso e, para
ambos casos de uso, deva-se realizar validação de dados através do método
ActionErrors validate(ActionMapping map, HttpServletRequest req), definido
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
43
em ActionForm, este atributo auxilia para que as validações sejam feitas de
acordo com a ação que representa determinada operação ou caso de uso.
Este mesmo atributo pode ser utilizado por uma action que possa realizar
mais de uma operação.
● data: utilizado quando o dado a ser submetido por um formulário refere-se à
uma data. No Struts 1, usado nos sistemas institucionais, caso haja a
necessidade de se informar uma data, deve-se informá-la em formato String e
posteriormente convertê-la para um objeto do tipo java.util.Date, por exemplo.
Para que não se fique replicando um atributo do tipo String para popular
datas, definiu-se este atributo data em AbstractForm, já que deve ser herdada
por todos os forms dos sistemas.
● invalidDate: armazena a informação se a data populada no atributo data,
como uma String, possui um formato válido. Ou seja, se a data foi inserida no
formato dd/MM/yyyy e se realmente existe.
● valor: utilizado quando o dado a ser submetido por um formulário refere-se a
um valor monetário. No Struts 1, usado nos sistemas institucionais, caso haja
a necessidade de se informar um valor monetário, deve-se informá-lo em
formato String e posteriormente convertê-la para um valor decimal, double,
por exemplo. Para que não se fique replicando um atributo do tipo String para
popular valores, definiu-se este atributo valor em AbstractForm, já que deve
ser herdada por todos os forms dos sistemas.
● invalidValor: armazena a informação se o valor populada no atributo valor,
como uma String, possui um formato válido. Ou seja, se o valor foi informado
no formato #,##0.00.
● Os principais métodos da classe AbstractForm são:
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
44
○ public void setData(String data): armazena a data populada através do
form e a atribui ao atributo data. Dentro deste método é feita uma
conversão da data no formato String, utilizando o método parseDate,
atribuindo ao atributo invalidDate a informação se a data possui ou não
formato válido.
○ public Date getDataObj(): método utilizado para converter a data no
formato String (atributo data) para um formato Date.
○ public Date parseDate(String data): método utilizado para converter
uma data qualquer no formato String passada como argumento em um
objeto do tipo Date.
○ protected void addErro(ActionErrors erros, String mensagem): método
utilizado para adicionar uma mensagem de erro (definida por uma
String definida em um arquivo .properties) ao objeto definido pelo
atributo ActionErrors erros.
○ public UsuarioGeral getUsuarioLogado(HttpServletRequest req) throws
ArqException: método que retorna um objeto que armazena os dados
do usuário logado na sessão web.
SigaaForm
SigaaForm é uma classe filha de AbstractForm que é utilizado no SIGAA para
guardar os dados de objetos que serão utilizados em casos de uso de cadastro. É
uma classe parametrizada e deverá ser estendida por outras classes para a
definição do tipo do objeto a ser utilizado no cadastro. Por exemplo: public class
PessoaForm extends SigaaForm<Pessoa> { ... } indica que a classe PessoaForm
será utilizada em casos de uso de cadastro e o objeto a ser cadastrado é do tipo
Pessoa.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
45
Dentre os seus atributos e métodos, é importante citar:
● obj: Objeto de domínio que contém os dados que serão cadastrados. Em
SigaaForm, esse atributo é parametrizado, mas irá assumir o tipo definido nas
subclasses que estenderem SigaaForm.
● confirm: Atributo do tipo boolean que é utilizado para armazenar a informação
de se o usuário confirma ou não uma determinada operação.
● mapa: Mapa com todos os objetos e coleções que serão utilizados para
pré-popular o form antes de exibi-lo. Esse mapa é chamado de “dados de
referência”, ou “reference data”.
● searchData: Lista com nomes de parâmetros em request que serão
considerados critérios de busca.
● clearReferenceData(): Limpa o mapa que contém os dados para popular o
form.
● formBackingObject(HttpServletRequest req): Pega um parâmetro de request
denominado id, busca no banco de dados o objeto da classe do form com o id
especificado e o retorna.
● validate(HttpServletRequest req): Valida os dados submetidos no formulário.
Por padrão, é chamado o método validate() da classe de domínio. Caso seja
necessário efetuar validações que não sejam as do validate() da classe de
domínio, deve-se sobrescrever este método nas classes filhas.
● referenceData(HttpServletRequest req): Método que deve ser sobrescrito
pelas classes filhas de SigaaForm para popular o mapa de dados de
referência.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
46
● customSearch(HttpServletRequest req): Cria uma busca definida pelo usuário
para ser utilizada na listagem do objeto do cadastro. Se retornar null o padrão
é utilizar findAll().
● registerSearchData(HttpServletRequest req): Informa ao form quais são os
atributos em request que são considerados parâmetros de busca
● unregisterSearchData(HttpServletRequest req): Retira os atributos
considerados parâmetros de busca de sessão.
● addAll(String attr, Class classe): Busca todos os objetos da classe
especificada no banco e as adiciona no mapa de dados de referência sob a
chave passada no primeiro parâmetro.
● addAll(String attr, Class classe, String orderBy, String ascDesc): Busca todos
os objetos da classe especificada no banco na ordem definida pelos
parâmetros orderBy e ascDesc e as adiciona no mapa de dados de referência
sob a chave passada no primeiro parâmetro. O parâmetro orderBy deve
conter o nome do atributo que será utilizado para ordenar os dados e o
parâmetro ascDesc é utilizado para definir se a ordenação é ascendente ou
descendente.
● addAllProjection(String attr, Class classe, String... fields): Busca todos os
objetos da classe especificada no banco, trazendo apenas os atributos
especificados no parâmetro fields, as adiciona no mapa de dados de
referência sob a chave passada no primeiro parâmetro.
● addAllProjection(String attr, String orderBy, String ascDesc, Class classe,
String... fields): Busca todos os objetos da classe especificada no banco na
ordem especificada pelos parâmetros orderBy e ascDesc. Além disso, ele traz
apenas os atributos especificados no parâmetro fields. Tais objetos serão
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
47
adicionados ao mapa de dados de referência sob a chave passada no
primeiro parâmetro.
● getPaging(HttpServletRequest req): Retorna as informações de paginação,
tais como o número de páginas, a página atual, etc. Usado pela tag
UFRN:table e pelos DAOs.
● getDAO(Class classe, HttpServletRequest req): Retorna uma instância do
DAO cuja classe foi passada como primeiro parâmetro. O DAO estará
populado com uma Session do Hibernate configurada para trabalhar com o
Datasource do SIGAA.
● getCurrentSession(HttpServletRequest req): Método utilizado pelo padrão
OpenSessionInView que retorna a Session do Hibernate que está
armazenada como atributo de request. Caso não exista o atributo em request
ou a session em request esteja fechada, umanova session é aberta e
associada ao request.
● beforePersist(HttpServletRequest req): Método chamado dentro do método
persist, de AbstractCrudAction, e deve ser sobrescrito pelas classes filhas de
SigaaForm caso seja necessário executar alguma operação com os dados do
form antes de persisti-los.
● getGenericDAO(HttpServletRequest req): Retorna uma instância de
GenericDAO populada com uma Session do Hibernate configurada para
trabalhar com o Datasource do SIGAA.
● clear(): Limpa os dados do objeto do form instanciando-o novamente.
● getSubSistemaCorrente(HttpServletRequest req): Retorna o subsistema que
está sendo utilizado atualmente pelo usuário. Essa informação é pega da
sessão do usuário.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
48
● getUnidadeGestora(HttpServletRequest req): Retorna o identificador da
unidade Gestora Acadêmica do usuário logado.
● getParametrosAcademicos(HttpServletRequest req): Retorna os parâmetros
acadêmicos armazenados em sessão.
● getNivelEnsino(HttpServletRequest req): Retorna o nível de ensino que está
atualmente associado ao usuário. Inicialmente, verifica qual o subsistema que
o usuário está utilizando e pega o nível de ensino desse subsistema. Caso o
nível de ensino não esteja definido para o subsistema, tentará pegar a
informação do nível da sessão. Se não encontrar, dispara uma ArqException
avisando que não foi possível descobrir o nível de ensino.
Arquitetura com JSF
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
49
A classe br.ufrn.arq.web.jsf.AbstractController é aquela que implementa todos os
comportamentos que os controladores utilizados no desenvolvimento de casos de
uso com JSF devem ter. Dessa forma, todos os Managed Beans desenvolvidos
devem herdar esses comportamentos.
br.ufrn.arq.web.jsf.AbstractController
Alguns dos comportamentos que todos os Managed Beans devem ter são:
● public static List<SelectItem> toSelectItems(Collection<?> col, String value,
String showText): transformar os objetos da coleção col passada como
argumento em uma lista de elementos do tipo javax.faces.model.SelectItem.
O parâmetro value é aquele que será armazenado no value da opção
selecionada. O parâmetro showText é a informação do objeto que será
exibida para seleção do usuário.
● public Collection<SelectItem> getAll(Class<?> classe, String value, String
text): realiza a consulta no banco de dados de todos os registros mapeados
pela classe classe passada como argumento e em seguida, transforma a
coleção de registros vindos do banco em uma lista de elementos do tipo
javax.faces.model.SelectItem. O parâmetro value é aquele que será
armazenado no value da opção selecionada. O parâmetro text é a informação
do objeto que será exibida para seleção do usuário.
● public <T> Collection<T> getAllObj(Class<T> classe, int sistema): retorna uma
coleção de objetos com dados dos registros no banco de dados mapeados
pela classe classe passada como argumento. Como existem três bancos de
dados nos sistemas institucionais, o parâmetro sistema indica para qual
banco é desejada realizar a consulta.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
50
● public void addMensagemErroPadrao(): adiciona uma mensagem de erro com
formato padrão que será exibida na aplicação ao usuário.
● public String tratamentoErroPadrao(Exception e): método que pode ser
utilizado durante o tratamento de alguma exceção via controlador web.
Através deste método, é enviado um email de erro à equipe de
desenvolvedores dos sistemas administrativos, indicando informações da
exceção ocorrida.
● public void addMensagemErro(String mensagem): adiciona uma mensagem
de erro com o texto passado pelo atributo mensagem que será exibida na
aplicação ao usuário.
● public void addMensagemWarning(String mensagem): adiciona uma
mensagem de warning com o texto passado pelo atributo mensagem que será
exibida na aplicação ao usuário.
● public void addMensagemInformation(String mensagem): adiciona uma
mensagem informativa com o texto passado pelo atributo mensagem que será
exibida na aplicação ao usuário.
● public void addMensagem(String codigo, Object... params): adiciona uma
mensagem de acordo com o código informado. As mensagens são
cadastradas no SIGAdmin e podem receber parâmetros no estilo do
String.format.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
51
http://java.sun.com/j2se/1.5.0/docs/api/java/lang/String.html#format(java.lang.String,%20java.lang.Object...)
http://java.sun.com/j2se/1.5.0/docs/api/java/lang/String.html#format(java.lang.String,%20java.lang.Object...)
● public void addMensagemErroAjax(String mensagem): adiciona uma
mensagem de erro com o texto passado pelo atributo mensagem. A
mensagem será exibida através de Ajax na jsp
/WEB-INF/jsp/include/errosAjax.jsp.
● public void addMensagemWarningAjax(String mensagem): adiciona uma
mensagem de warning com o texto passado pelo atributo mensagem. A
mensagem será exibida através de Ajax na jsp
/WEB-INF/jsp/include/errosAjax.jsp.
● public void addMensagemInfoAjax(String mensagem): adiciona uma
mensagem informativa com o texto passado pelo atributo mensagem. A
mensagem será exibida através de Ajax na jsp
/WEB-INF/jsp/include/errosAjax.jsp.
● public boolean hasOnlyErrors(): indica se mensagens de erro foram
adicionadas a sessão.
● public Object execute(Movimento mov) throws NegocioException,
ArqException: Recebe um objeto br.arq.dominio.Movimento e permite a
comunicação com o EJB, representado pelo processador, onde é executada a
lógica de negócio. O processador é selecionado de acordo com um código de
movimento, obtido através do método de assinatura br.arq.dominio.Comando
getCodMovimento() implementado em classes que implementam a interface
Movimento.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
52
● public Object executeWithoutClosingSession(Movimento mov) throws
NegocioException, ArqException: mesma função do método anterior, porém
no método anterior a conexão com a base de dados é fechada ao final de sua
execução. Com este outro método, a conexão permanecerá aberta.
● public void prepareMovimento(Comando comando) throws ArqException:
habilita um processador de ter o seu código executado mais uma vez. O
processador habilitado é aquele que corresponde ao código de movimento
(identificador) passado como argumento. O dado da requisição web é
utilizado para a verificação de informações referente ao usuário logado
presente na sessão web. Após a execução do código presente em um
processador, ele é novamente bloqueado.
● public String forward(String szPage): realize forward para páginas JSP
navegadas por casos de uso em JSF. Na arquitetura que foi definida, o fluxo
de navegação entre JSPs não foi definido através de arquivos de
configurações XML.
● public String redirect(String url): método utilizado para redirecionar URLs em
casos de uso desenvolvidos em JSF.
● public HttpServletRequest getCurrentRequest():retorna um objeto
HttpServletRequest que representa a requisição atual.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
53
● public HttpServletResponse getCurrentResponse():retorna um objeto
HttpServletResponse que representa a resposta atual.
● public HttpSession getCurrentSession():retorna um objeto HttpServletSession
que representa a sessão atual.
● public String getParameter(String param): retorna o contéudo (formato String)
de um parâmetro web passado como argumento.
● public String cancelar(): método genéricoque implementa o comportamento
de uma ação de cancelamento de operação. Basicamente, redireciona a
navegação para a visualização que representa o menu de onde se iniciou o
caso de uso. Se tiver sido acionada através de um Managed Bean no escopo
de sessão, remove o mesmo da sessão.
AbstractControllerCadastro
A classe br.ufrn.arq.web.jsf.AbstractControllerCadastro herda de AbstractController
todos os seus comportamentos. É uma classe que representa um controlador com
métodos úteis ao cadastro, atualização e remoção de dados de entidades no banco
de dados.
Durante o desenvolvimento de casos de uso que realizam persistência na base de
dados, o controlador que auxilia o desenvolvimento deve herdar a classe
AbstractControllerCadastro e se for útil, invocar os métodos disponíveis e
implementados nela. Se não houver nenhuma regra de negócio envolvida no caso
de uso, (casos de uso CRUDs) esta classe dá total suporte ao seu desenvolvimento.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
54
A classe AbstractControllerCadastro possui uma estrutura que permite qualquer
Managed Bean que herde dela implementar um caso de uso CRUD com o mínimo
de codificação possível. Em geral, o caso de uso é utilizado para realizar a
persistência dos dados populados em um objeto (mapeado pelo Hibernate) em sua
tabela correspondente no caso de uso, sem regras de negócio. O seu
desenvolvimento pode ser formado basicamente por três JSP’s com seguintes
nomes padronizados:
● form.jsp: JSP que conterá o formulário onde serão informados os dados a
serem persistidos. Cada submissão do formulário popula uma linha em uma
tabela do banco de dados, definida no caso de uso.
● lista.jsp: JSP que lista todas as informações das linhas da tabela onde os
dados foram persistidos. A tabela de onde virão os dados corresponde a
mapeada por uma classe pré-definida.
● view.jsp: JSP que exibe as informações de uma linha de uma tabela
representada por um objeto no momento da exibição. Por padrão, estas JSPs
devem ficar em um diretório base formado por um diretório padrão, definido
pela aplicação e concatenado com o nome da classe que irá realizar a
persistência objeto-relacional. Por exemplo, para a persistência de dados
mapeado pela classe br.ufrn.sigaa.prodocente.producao.dominio.Livro, por
padrão, as JSPs devem ficar no diretório padrão /prodocente/producao/Livro/,
onde /prodocente/producao/ é a parte do diretório definido pela aplicação e
Livro/ corresponde a um subdiretório definido pelo nome da classe que terá
seus dados persistidos na base de dados.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
55
O auxilio da classe AbstractControllerCadastro no desenvolvimento dos casos de
uso CRUD parte da utilização das JSPs definidas anteriormente. Alguns atributos
definidos nesta classe são:
● T obj: objeto genérico definido em AbstractControllerCadastro. O tipo do
objeto deve ser definido no momento que um managed bean herda esta
classe.
● String confirmButton: define o nome do botão presente no formulário para
realização de operações de cadastro, alteração ou remoção de um dado.
● boolean readOnly: caso assuma o valor true indica que todos os componentes
que compõe o formulário serão de somente leitura. Por padrão, é definido
com o valor false.
● Collection<T> resultadosBusca: coleção que pode ser utilizada para
armazenar um conjunto de objetos genéricos T retornados de alguma
consulta ao banco de dados.
● Collection<T> all: coleção que pode ser utilizada para armazenar um conjunto
de objetos genéricos T que correspondem a todas as linhas da tabela
mapeada pelo objeto definido em T. Alguns métodos definidos nesta classe
estão definidos abaixo. Todos esses métodos podem ser redefinidos nas
subclasses de AbstractControllerCadastro.
● public String getDirBase(): retorna o diretório base onde as JSP utilizadas no
desenvolvimento do caso uso estão.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
56
● public String getConfirmButton(): retorna o nome atual do botão de
confirmação da operação (confirmButton), ou seja, do botão que irá submeter
um formulário web.
● public String getFormPage(): retorna o nome da JSP utilizada como formulário
para cadastrar ou alterar os dados de um objeto persistente T.
● public String getViewPage(): retorna o nome da JSP utilizada para exibir os
dados de um objeto persistente T.
● public String getListPage(): retorna o nome da JSP utilizada para listar todos
os objetos T persistidos na base de dados.
● public String cadastrar() throws SegurancaException, ArqException,
NegocioException: método utilizado para persistir os dados do objeto T em
sua tabela correspondente na base de dados. Lembrando que a persistência
de T não é antecedida de nenhuma validação de regra de negócio, nem há o
envolvimento de persistência de outros objetos. A persistência é realizada
através de um objeto ProcessadorCadastro.
● public String preCadastrar() throws ArqException,NegocioException: método
invocado para redirecionar à navegação à página JSP que possui o formulário
web.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
57
● public void beforeCadastrarAndValidate() throws NegocioException,
SegurancaException, DAOException: método invocado dentro do método
cadastrar antes do trecho que realiza validações básicas dos dados
submetidos no formulário web. Por exemplo, antes de validação de campos
obrigatórios, com formatos válidos, etc.
● public void beforeCadastrarAfterValidate() throws NegocioException,
SegurancaException, DAOException: método invocado dentro do método
cadastrar após o trecho que realiza validações básicas dos dados submetidos
no formulário web. Por exemplo, após a validação de campos obrigatórios,
com formatos válidos, etc.
● protected void afterCadastrar() throws ArqException: método invocado dentro
do método cadastrar após o trecho que invoca o processador responsável
pela persistência.
● public String forwardCadastrar(): método que retorna a JSP para a qual o
fluxo deve ser redirecionado após a execução do método cadastrar.
● public String listar() throws ArqException: método que retorna a JSP para a
qual o fluxo deve ser redirecionado quando se deseja listar todos os objetos T
persistidos.
● public String atualizar() throws ArqException: método invocado para
redirecionar a navegação à página JSP que possui o formulário web para a
alteração dos dados do objeto persistente T.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
58
● public void afterAtualizar(): método invocado dentro do método atualizar antes
do redirecionamento para a página JSP para a alteração dos dados.
● public String remover() throws ArqException: método utilizado para remover
os dados do objeto T de sua tabela correspondente na base de dados. A
remoção também é realizada através de um objeto ProcessadorCadastro.
● public String preRemover(): método invocado para redirecionar a navegação à
página JSP que possui o formulário web para confirmação da remoção dos
dados do objeto peristente T.
● public void afterPreRemover(): método invocado dentro do método
preRemover antes do redirecionamento para a página JSP para a
confirmação da remoção.
● public void beforeRemover() throws DAOException: método invocado dentro
do método remover antes da invocação do processador responsável pela
remoção do dado.
● public void afterRemover(): método invocado dentro do método remover após
a invocação do processador responsável pela remoção do dado.
● protected String forwardRemover():método que retorna a JSP para a qual o
fluxo deve ser redirecionado após a execução do método remover.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
59
Para cada sistema, existe uma classe que representa o controlador básico para o
desenvolvimento dos casos de uso dentro do sistema. Na Figura 8.3, estes
controladores herdam a classe AbstractControllerCadastro e estão representados
pelas classes :
● br.ufrn.sigaa.arq.jsf.SigaaAbstractController: controlador intermediário para o
desenvolvimento do SIGAA.
● br.ufrn.sipac.arq.jsf.SipacAbstractController: controlador intermediário para o
desenvolvimento do SIPAC.
● br.ufrn.sigrh.arq.jsf.SigrhAbstractController: controlador intermediário para o
desenvolvimento do SIGRH.
● Alguns dos métodos presentes nos três controladores possuem o mesmo
propósito. Os principais são:
○ getUsuarioLogado(): retorna o usuário logado autenticado no sistema.
○ getGenericDAO(): retorna um Data Access Object (DAO – Ver camada
de mapeamento), responsável por permitir a comunicação entre a
aplicação e a base de dados.
○ getAcessoMenu(): retorna um objeto que que define o nível de acesso
a algumas operações no sistema.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
60
○ checkRole(int papel): verifica se o usuário logado possui um
determinado papel passado como argumento.
○ getUnidadeGestora(): retorna o identificador da unidade gestora do
usuário logado.
○ cancelar(): método genérico para cancelar a operação durante o fluxo
do caso de uso. Basicamente remove o managed bean de sessão
(caso esteja) e redireciona o fluxo de navegação para o menu de onde
se iniciou a execução a operação. Cada sistema possui um conjunto de
subsistemas com seus respectivos menus.
Mensagens aos usuários
Ver:
https://docs.info.ufrn.br/doku.php?id=desenvolvimento:especificacoes:arquitetura:me
nsagens
Converter Personalizados
Os conversores são usados para converter entrada de string em tipos de dados Java
para várias finalidades. As conversões são realizadas antes do início do processo de
validação. Se um usuário fornecer um valor que a aplicação não possa converter no
tipo de dados especificado, a aplicação Web rejeita a entrada e envia uma
mensagem de erro.
O JSF já disponibiliza um conjunto de conversores. Na arquitetura dos sistemas
institucionais, também há um conjunto de conversores desenvolvidos e disponíveis:
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
61
https://docs.info.ufrn.br/doku.php?id=desenvolvimento:especificacoes:arquitetura:mensagens
https://docs.info.ufrn.br/doku.php?id=desenvolvimento:especificacoes:arquitetura:mensagens
https://docs.info.ufrn.br/doku.php?id=desenvolvimento:especificacoes:arquitetura:mensagens
● CepConverter: converter uma String no formato padrão de um CEP (Ex.:
59067-710) para um valor inteiro (Ex.: 59067710) e vice versa.
● CpfConverter: converter uma String no formato padrão de um CPF (Ex.:
196.918.397-76) para um valor long (Ex.: 19691839776) e vice versa.
● HoraConverter: converter uma String no formato padrão de hora (Ex.: 09:30)
para um valor do tipo java.util.Date e vice versa.
● DateConverter: converter uma String no formato padrão de data (Ex.:
23/06/2008) para um valor do tipo java.util.Date e vice versa.
● ValorMoedaConverter: converter uma String no formato de um valor
monetário (Ex.: 100,50 ) para um valor do double e vice versa.
● SimNaoConverter: converter um valor boolean para a String “Sim” em caso de
verdadeiro e “Não” em caso de falso.
Tag Libraries Importantes
A arquitetura disponibiliza um conjunto de tag libraries que auxiliam no
desenvolvimento dos casos de uso dos sistemas. A Figura 8.5 apresenta as classes
que representam as tags disponíveis mais importantes.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
62
Resumidamente, cada uma dessas tags são usadas para:
● BuscaCodigoTag: usada para auxiliar a busca de elementos em um
combobox através de um código.
● ButtonTag: usada para inserir botões de ações independente da existência de
um formulário.
● FormatTag: usada para realizar formatação de dados. Formatação de data,
cpf, cnpj, valor monetário, etc.
● HelpTag: usada para incluir informações de ajuda ao longo de páginas dos
casos de uso. Uma interrogação é incluída na tela e quanto se passa o mouse
em cima, uma informação explicativa aparece.
● LinkSubsistemaTag: usada para a geração de um link para o menu do
subsistema indicado em request ou passado como parâmetro.
● LinkTag: usada para inserir links de ações independente da existência de um
formulário.
● MathTag: usada para realizar operações matemáticas entre dois valores
informados
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
63
● MultiplicarTag: usada para realizar a operação de multiplicação entre dois
valores informados
● SelectAnoTag: usada para a geração dinâmica de um combobox com um
conjunto de valores de anos, com a opção pré-selecionada para o ano atual
ou para um valor pré-determinado.
● SelectEstadoTag: usada para a geração dinâmica de um combobox com
todos os estados brasileiros para seleção.
● SelectMesTag: usada para a geração dinâmica de um combobox com todos
os meses do ano, com a opção pré-selecionada para o mês atual ou para um
valor pré-determinado.
● StepTag:
● TableTag:
● UnidadeTag: usada para a geração dinâmica de um combobox com um
conjunto de unidades para seleção. Formada por um conjunto de parâmetros
que indicarão quais unidades farão parte do combobox, por exemplo, se
somente as orçamentárias, as gestoras, as filhas de determinada unidade,
etc.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
64
Utilitários
A arquitetura dos sistemas institucionais disponibiliza de um conjunto de classes
úteis para o desenvolvimento dos mesmos. Essas classes disponibilizam e
encapsulam um conjunto de funcionalidades comuns durante o desenvolvimento de
vários casos de uso.
Logging
Log de Visualização
Cada operação de um usuário nos sistemas, tais como cliques em links, envios de
formulários, etc, é registrada em log. Esse log fica armazenado em bancos de dados
diferentes dos bancos dos sistemas: os bancos de logs. Cada ação dos usuários é
interceptada pelo ViewFilter, que registra a ação executada através de métodos da
classe UserAgent.
Para operações realizadas nas partes internas dos sistemas, é utilizado o método
logaOperacao. Para as operações realizadas nas partes públicas dos sistemas, é
utilizado o método logaOperacaoPublica. Nesses métodos são registradas
informações como a URL que o usuário acessou, o user agent do usuário, o registro
de entrada (caso seja em parte interna), os parâmetros de request, o tempo
necessário para executar a ação e informações sobre algum erro que tenha
acontecido.
Para realizar consultas no log de operações, é necessário acessar o SIGAdmin. No
menu Auditoria, existem duas opções: Consultar Registro de Entrada e Consultar
Registro de Acesso Público , conforme mostrado na figura abaixo. Essas opções são
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
65
utilizadas, respectivamente, para consultar as ações de usuários logados e as ações
realizadas na parte pública dos sistemas.
Nas consultas, o usuário pode buscar os dados dos registros de entrada de acordo
com os critérios de busca oferecidos. Um exemplo pode ser visto abaixo:
Após realizar a consulta, aparecerãoos diversos registros de entrada / registros de
acesso público encontrados. Para visualizar as operações realizadas durante esse
registro, basta clicar no ícone da lupa.
Log de Banco de Dados
Modificações em entidades realizadas pelo Hibernate são armazenadas em um
banco de dados chamado LogDB. Essas modificações são registradas por um
interceptor do Hibernate implementado em br.ufrn.arq.seguranca.log.LogInterceptor.
Nesse log são armazenadas informações sobre a operação realizada no banco de
dados, o timestamp em que foi realizada a operação, a entidade envolvida, a chave
primária da entidade e os dados alterados.
Para realizar consultas no LogDB, deve-se ir ao SIGAdmin e acessar o link Auditoria
→ Consultar LogDB. A tela mostrada na figura abaixo irá aparecer. Nela, podemos
buscar as alterações em uma entidade de acordo com o seu nome e o seu id.
Podemos filtrar ainda os tipos de operações que foram realizadas com a entidade
(inserção, atualização, remoção).
Após informar os dados necessário à consulta, a lista de operações realizadas com
a entidade informada irá aparecer, conforme mostrado na figura abaixo.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
66
Log de Chamada de Processadores
Existe ainda um outro tipo de log disponibilizado pela arquitetura: o log de chamada
dos processadores, também chamado de LogMovimento. Cada vez que um
processador é chamado, são armazenadas informações sobre o código do
movimento executado, a data de execução, o sistema a partir do qual o comando foi
executado, o id do movimento e o id do registro de entrada. Essas informações são
captadas na classe LogProcessorDelegate, através do método writeMovimentoLog.
Para consultas, deve-se acessar o SIGAdmin e utilizar o link Auditoria → Extrato
Diário de Movimentação, onde é possível consultar os movimentos do sistema
acadêmico e dos administrativos. Nessa opção, são mostrados os movimentos
realizados no dia, conforme mostra a figura abaixo.
Log de Atualizações realizadas via JDBC
Ver detalhes em:
https://docs.info.ufrn.br/doku.php?id=desenvolvimento:especificacoes:sigadmin:caso
s_de_uso:auditoria:log_jdbc
Da assincronia dos logs
Os logs acima descritos são assíncronos, de forma que eles não são gravados assim
que criados pela classe responsável. A classe que cria o log e é chamada no
ViewFilter, ou no interceptor, etc., grava os dados do log em uma fila dá um notify
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
67
https://docs.info.ufrn.br/doku.php?id=desenvolvimento:especificacoes:sigadmin:casos_de_uso:auditoria:log_jdbc
https://docs.info.ufrn.br/doku.php?id=desenvolvimento:especificacoes:sigadmin:casos_de_uso:auditoria:log_jdbc
https://docs.info.ufrn.br/doku.php?id=desenvolvimento:especificacoes:sigadmin:casos_de_uso:auditoria:log_jdbc
em uma thread chamada LogConsumer. Essa thread irá pegar os dados das filas e
gravar no banco de dados de forma assíncrona, evitando que o desempenho do
sistema seja afetado pela gravação de logs.
A gravação de dados em filas que serão consumidos por uma outra thread
caracteriza o problema do log descrito acima como um Problema do
Produtor/Consumidor.
Logs inseridos pelos desenvolvedores
Ver detalhes em:
https://docs.info.ufrn.br/doku.php?id=desenvolvimento:especificacoes:sigadmin:caso
s_de_uso:auditoria:consulta_log_servidor
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
68
http://en.wikipedia.org/wiki/Producer-consumer_problem
http://en.wikipedia.org/wiki/Producer-consumer_problem
http://en.wikipedia.org/wiki/Producer-consumer_problem
https://docs.info.ufrn.br/doku.php?id=desenvolvimento:especificacoes:sigadmin:casos_de_uso:auditoria:consulta_log_servidor
https://docs.info.ufrn.br/doku.php?id=desenvolvimento:especificacoes:sigadmin:casos_de_uso:auditoria:consulta_log_servidor
https://docs.info.ufrn.br/doku.php?id=desenvolvimento:especificacoes:sigadmin:casos_de_uso:auditoria:consulta_log_servidor
Classes Utilitárias
A Figura abaixo apresenta um conjunto de classes disponíveis na arquitetura com
algumas operações.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
69
Abaixo um detalhamento melhor cada uma dessas classes:
● CalUtils: classe que disponibiliza um conjunto de métodos relacionados a
datas, como por exemplo: formatação de datas, verificação se determinada
data cai em um final de semana, busca pelo próximo dia da semana após
determinada data.
● CodigoBarraServlet: classe servlet que disponibiliza métodos para a criação e
exibição de códigos de barras.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
70
● DataUtils: classe que disponibiliza um conjunto de métodos que implementam
operações comuns sobre datas. Por exemplo: cálculo da quantidade de dias,
meses e anos entre duas datas, método que retorna um objeto Date
considerando apenas informações de dia, mês e ano, ou seja,
desconsiderando informação de hora.
● EqualsUtil: Classe que possui métodos que facilitam a implementação do
método equals(Object obj) nas classes de domínios dos sistemas.
● ErroUtils: classe que disponibiliza métodos auxiliares para a notificação de
erros. Disponibiliza também um método que notifica por email caso alguma
exceção que represente falha ocorra no sistema.
● EstadoHelper: classe com métodos que realizam a verificação referente aos
estados brasileiros. Possui dois vetores, um de siglas e outro de nomes que
representam os estados do Brasil.
● Extenso: classe que possui métodos que auxiliam a escrita de números por
extenso.
● FileLogger: logador em arquivo. Esta classe é usada no caso de algum
processo precisar logar em um arquivo.
● Formatador: classe que possui métodos que auxiliam na formatação de
dados. Por exemplo, formatação de datas no formato dd/MM/yyyy, formatação
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
71
de horas no formato HH:mm:ss, formatação de CEPs, de valores numéricos
que representam moedas, etc.
● HashCodeUtil: classe que possui métodos que facilitam a implementação do
método hashCode() nas classes de domínios dos sistemas.
● HibernateUtils:
● ImageUtil:
● ImageUtils: classe com métodos auxiliares para o tratamento de imagens.
Métodos para redimensionamento de imagens, criação e recorte de imagem,
aplicação de filtros, etc.
● JasperReportsUtil: classe que auxilia na exportação de relatórios para os
diferentes formatos disponíveis, por exemplo: PDF, XLS, HTML.
● Link: classe de domínio que representa a informação de um link. Possui
atributos que representam o título e a URL do link.
● ParametroHelper: diversas informações são parametrizadas nos sistemas em
uma tabela na base de dados, como por exemplo, os limites mínimos e
máximos de licitações, prazos para bloqueios de operações, valores de taxas,
etc. No momento em que se precisa recuperar os valores desses parâmetros,
deve-se utilizar esta classe auxiliar.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
72
● ProtocoloUtil: classe que possui métodos que auxiliam algumas operações no
subsistema de Protocolo e Documentos. Os processos protocolados possuem
um número com uma formatação específica e um dígito verificador definido
através de determinada regra. Esta classe possui métodos que auxiliam a
formatação do número e dígito verificador de processos protocolados.
● ReflectionUtil: classe utilitária para auxiliar o trabalho com a API de Reflection.
● RequestUtils:classe Utilitária para trabalhar com HttpServletRequest.
● Step:
● StringUtils: classe que possui métodos úteis quando se trabalha com objetos
String. Apresenta métodos para verificação se determinada String é vazia,
conversão de String para a codificação Latim 9, verificação se a String possui
números, etc.
● UFRNUtils: classe utilitária geral disponível na arquitetura dos sistemas.
Possui diversos métodos, como por exemplo: métodos que retornam mês e
ano atual, que convertem datas para formatos especificados, para conversão
de uma Collection em ArrayList, etc.
● ValidadorCPFCNPJ: classe que disponibiliza métodos para validação de
números de CPF e CNPJ.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
73
● ValidatorUtil: classe que possui métodos que auxiliam a validação de diversos
tipos de dados. Por exemplo: validação de formato de data, CPF, CNPJ, RG,
telefone, email, se números são maiores que zero, etc.
Autenticação
Acesso de usuários com múltiplos vínculos
Alguns usuários dos sistemas corporativos da UFRN podem possuir mais de um
vínculo com a universidade e devem interagir com os sistemas de formas diferentes
para cada um desses vínculos. Por exemplo, uma pessoa pode ser servidora da
universidade e fazer algum curso de graduação. Nesse contexto, essa pessoa
possui dois vínculos com a universidade: o vínculo de servidor e o vínculo de
discente. Os possíveis vínculos com a universidade são: discente, servidor, docente
externo, tutor orientador e coordenador de pólo de ensino à distância.
A existência de múltiplos vínculos é encarada de formas diferentes pelos sistemas.
No sistema acadêmico (SIGAA), é necessária a escolha de um entre os vínculos
possíveis do usuário. A partir daí, o vínculo escolhido passa a ser o vínculo ativo que
será utilizado para realizar as operações no sistema. Para o sistema de recursos
humanos (SIGRH), só é necessária a escolha de um vínculo se o usuário possuir
mais de um registro como servidor, ou seja, tiver mais de uma matrícula SIAPE, caso
contrário será escolhido automaticamente o seu vínculo de servidor que estiver ativo.
No sistema administrativo (SIPAC), a existência de múltiplos vínculos não afeta as
operações do usuário, não sendo, portanto, necessária a escolha de um vínculo
entre os existentes.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
74
O processamento dos possíveis vínculos do usuário é feito durante o seu login nos
sistemas. Nesse momento, todos os possíveis vínculos do usuário são buscados e
armazenados em um atributo transiente (que não é persistido em banco de dados)
da classe Usuario chamado vinculosUsuario. Esses vínculos do usuário são, então,
marcados como ativos ou não. Por exemplo, um servidor da universidade é um
vínculo ativo, um servidor aposentado é um vínculo inativo; um discente é um vínculo
ativo, enquanto que um discente que já concluiu o curso é um vínculo inativo.
Se o usuário possuir apenas um vínculo ativo, esse é escolhido como o principal
para o usuário utilizar no momento. Se ele possuir mais de um vínculo ativo, será
apresentada uma tela para que seja escolhido, dentre seus vínculos, qual o desejado
para ser utilizado naquele momento (Figura 9.9). Se não possuir nenhum vínculo
ativo, será utilizado, automaticamente, o mais recente vínculo inativo. O vínculo
escolhido para ser o principal é armazenado no atributo vinculoAtivo da classe
Usuario.
Para o SIGRH isso não é necessário, sendo suficiente buscar os servidores
associados ao usuário e direcionar o vínculo escolhido no atributo servidor da classe
Usuario.
No SIGAA, a classe responsável pelo processamento dos vínculos de um usuário é
a br.ufrn.sigaa.dominio.VinculoUsuario e a
br.ufrn.sigrh.arq.jsf.VinculosServidorMBean no SIGRH. No SIGAA, existe ainda a
classe br.ufrn.sigaa.arq.struts.EscolhaVinculoAction, responsável por fazer a seleção
do vínculo quando a tela de escolha de vínculos é apresentada ao usuário.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
75
Processamento de Permissões dos Usuários
Após o login de um usuário nos sistemas corporativos, é necessário realizar um
processamento para verificar quais permissões o usuário terá para acessar as
funcionalidades do sistema. Esse processamento é feito em uma classe denominada
AcessoMenu, presente em todos os sistemas. Ela realiza a busca das permissões
dos usuários que foram cadastradas no banco de dados (permissões persistidas) e
verifica quais permissões o usuário tem baseado em outras informações persistidas,
como seu cargo na instituição. Essas últimas são chamadas de permissões
temporárias.
As possibilidades de permissões temporárias são muitas e variam de acordo com os
subsistemas existentes. Inicialmente, a classe AcessoMenu realizava o
processamento de todas as permissões temporárias de todos os subsistemas, o que
a tornava extremamente grande e difícil de manter. Para reduzir esse problema, o
AcessoMenu monolítico foi substituído por um AcessoMenu dividido em diversas
classes, uma para cada subsistema, cujo processamento era realizado com base no
padrão de projeto Chain of Responsibility.
O padrão de projeto Chain of Responsibility consiste em um objeto de comando e
um conjunto de objetos de processamento, formando uma cadeia de
processamento. Cada objeto de processamento contém um conjunto de lógica que
descreve o que ele deve fazer e como passar o processamento para um próximo
objeto da cadeia. No objeto de comando deve existir código para criação da cadeia e
para início da execução do processamento.
As informações de acesso do usuário, como por exemplo, os subsistemas que o
usuário pode acessar, são guardadas em uma classe chamada DadosAcesso, que é
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
76
armazenada na sessão HTTP através do atributo de nome acesso e podem ser
acessadas a qualquer momento.
Envio de E-Mails
Diversas operações do sistema são complementadas com o envio de emails
informativos. Por exemplo, no envio, autorização de requisições, emails informativos
diários sobre pagamentos efetuados em contratos, obras prestes a vencer, etc. Para
que os emails sejam enviados de forma facilitada e assíncrona, a arquitetura
disponibiliza um conjunto de classes como mostrado na Figura 9.10.
O envio de email é feito através da invocação de um dos métodos send da classe
br.ufrn.arq.email.Mail.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
77
Tratamento de Exceções
A Figura 11.1 apresenta as classes que representam algumas das exceções que
podem ser disparadas nos códigos fontes dos casos de uso dos sistemas
institucionais. Todas as exceções herdam de UFRNException. A exceção
ArqException representa exceções que podem ser disparadas pela arquitetura dos
sistemas. DAOException encapsula exceções relacionadas à base de dados.
HostNaoAutorizadoException pode ser disparada para não permitir que o acesso via
algum host não seja feito. SegurancaException é disparada quando há violação de
segurança da arquitetura. LimiteResultadosException é disparada quando alguma
consulta é feita na base de dados e o resultado excede um limite de linhas
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
78
pré-definido. NegocioException é utilizada para disparar exceções relacionadas à
violação de regras de negócio.
É importante saber que o tratamento de algumas dessas exceções de forma
incorreta pode silenciar erros indevidamente, evitando que a equipe de
desenvolvimento ou o usuário seja informadoque algum erro está ocorrendo. Em
geral, deve-se disparar todas essas exceções, exceto exceções do tipo
NegocioException, que as mesmas serão tratadas pela infra-estrutura da arquitetura.
As exceções do tipo NegocioException devem ser tratadas, de forma que seja
indicado ao usuário de forma clara a violação da regra de negócio.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
79
Tarefas Assíncronas
Tarefas assíncronas são aquelas executadas sem que haja uma necessidade de
resposta imediata. Diversas operações dos sistemas institucionais devem ser feitas
assincronamente, por exemplo:
● No SIGAA, os alunos podem solicitar trancamento de matrículas em
disciplinas pelo próprio sistema. Este trancamento é confirmado
automaticamente pelo sistema, através de uma tarefa assíncrona, após sete
dias. Isto acontece porque foi definido que caso um aluno deseje trancar uma
matrícula em disciplina, não há necessidade de que nenhuma autorização por
parte dos dirigentes acadêmicos.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
80
● Diariamente há a necessidade que dados de recursos humanos sejam
migrados do banco de dados administrativo para o banco acadêmico. Dessa
forma, esta tarefa também é automatizada de forma assíncrona.
● As bases de dados dos sistemas são alimentadas constantemente por
usuários de setores distintos. Em algumas situações, há a necessidade de
que dirigentes superiores desses setores sejam informados com resumos do
que foi lançado em determinado período. Essa informação é enviada
periodicamente para estes dirigentes por email e isto é feito também através
de uma tarefa assíncrona. Algumas dessas informações são: obras a vencer,
pagamentos efetuados em contratos, bens tombados no dia, atendimentos
realizados no almoxarifado, etc.
Criando uma classe Timer
Uma tarefa assíncrona é representada por uma classe br.ufrn.arq.task.TarefaTimer,
representada por uma Thread. Ela possui um conjunto de atributos que indica qual a
periodicidade que a tarefa assíncrona e em que servidor será executada. Todas as
classes envolvidas na criação de uma classe Timer podem ser vistas na Figura 12.1.
A No momento em que se desejar criar uma tarefa assíncrona nos sistemas, deve-se
criar uma classe quer herda TarefaTimer e inserir um registro na tabela
INFRA.REGISTRO_TIMER (Banco SISTEMAS_COMUM) que possuirá informações
sobre a periodicidade que a tarefa assíncrona e em que servidor será executada. Na
Figura 12.2, pode-se observar o registro de sete tarefas assíncronas que são
executadas.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
81
Em relação a cada atributo da classe TarefaTimer:
● idTarefa: identificador da tarefa.
● expressaoCron: Expressão do CRON que indica quando a tarefa deverá ser
executada. Pode ser gerada através do site http://www.cronmaker.com/.
● ultimaExecucao: armazena a data e hora da última execução do timer.
● servidorRestricao: servidor em que a tarefa será executada.
A classe br.ufrn.comum.timer.TimerConsultas herda de TarefaTimer e é utilizada por
classes timers que realizam consultas SQL utilizando os benefícios da classe
JDBCTemplate disponibilizada pelo framework Spring.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
82
http://www.cronmaker.com/
http://www.cronmaker.com/
A classe br.ufrn.arq.tasks.TarefaScheduler é uma classe thread que funciona como
escalonador que coloca as tarefas timers em execução. Em relação aos seus
principais métodos:
● public void carregaTarefas():.carrega as classes que representam os timers
através dos registros inseridos na tabela REGISTRO_TIMER (Figura 12.2). A
coluna ATIVA indica quais timers podem ser executados no momento, ou
seja, aqueles que a linha na tabela estão com ATIVA = TRUE.
● public void run():.invoca o método que carrega as classes timers e executa
cada tarefa de acordo com sua periodicidade.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
83
● public void atualizaExecucao( int idTarefa ): método que atualiza a data e hora
da última execução de determinada tarefa.
_____
Superintendência de Informática
Universidade Federal do Rio Grande do Norte
sinfo.ufrn.br
84