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