ARQUITETURA SISGRAD
Manual de Utilização
Versão: 2.0
Criação: 05 de julho de 2007
Autor: André Penteado
Última Revisão: 09 de outubro de 2009
Autor: Alessandro Moraes
Sumário
Sumário
1.ESTRUTURA DE APLICAÇÕES WEB
1.ESTRUTURA DE APLICAÇÕES WEB
...
...
3
3
2.ARQUITETURA
2.ARQUITETURA
...
...
4
4
a)Bibliotecas e Ferramentas...4
b)Outros Recurso...5
c)Principais Fluxos...5
3.BEANS
3.BEANS
...
...
6
6
4.AÇÕES
4.AÇÕES
...
...
7
7
a)Configuração do Fluxo...7
b)Validações de Dados...7
c)Tratamento de Erros...8
5.SERVIÇOS
5.SERVIÇOS
...
...
8
8
a)Instanciação de Objetos de Serviço...8
b)Auditoria e Validações de Negócio...9
c)Tratamento de Erros...9
6.AUTORIZAÇÃO
6.AUTORIZAÇÃO
...
...
9
9
7.CONFIGURAÇÕES DE SISTEMA
7.CONFIGURAÇÕES DE SISTEMA
...
...
10
10
8.PADRONIZAÇÃO DE CÓDIGO
8.PADRONIZAÇÃO DE CÓDIGO
...
...
11
11
a)Sufixos nos nomes de classes...11
b)Nomes de métodos de busca...11
c)Nomes de métodos de alteração no banco de dados...11
9.IMPLANTAÇÃO
ESTRUTURA DE APLICAÇÕES WEB
Embora existam diversos servidores web para rodar aplicações Java, suas estruturas são semelhantes. A estrutura de diretórios apresentada a seguir refere-se ao Apache Tomcat versão 6, disponível em http://tomcat.apache.org: - apache-tomcat-6.0.18 - bin - conf - lib - logs - temp + webapps + work
Os nomes dos diretórios são auto-explicativos, cabendo apenas lembrar que as bibliotecas Java adicionadas ao diretório lib poderão ser acessadas por todas as aplicações instaladas neste servidor.
No diretório webapps estarão as aplicações Java, cuja estrutura nos convém detalhar
um pouco mais:
Diretório O que é
/minhaAplicacao Diretório principal da aplicação Web. Todos
os arquivos JSP* e XHTML estão aqui.
/minhaAplicacao/WEB-INF Diretório que contém todos recursos relacionados a aplicação, organizados em pastas e arquivos que serão detalhadas a seguir.
Este diretório não é público, ou seja, todo arquivo e diretório contido nele não pode ser acessado diretamente pelo cliente.
/minhaAplicacao/WEB-INF/web.xml Arquivo XML com diversas definições a respeito da aplicação, tais como Servlets e Filters. /minhaAplicacao/WEB-INF/classes Diretório onde estão localizados as classes
Java, organizadas em subdiretórios conforme seus pacotes.
/minhaAplicacao/WEB-INF/classes/br/unesp/actions
Exemplo de um diretório que contém as classes do pacote br.unesp.actions.
/minhaAplicacao/WEB-INF/lib Diretório onde devem ser adicionados os arquivos de bibliotecas e taglibs a serem utilizados pela aplicação. Ex.: JDBCs, bibliotecas de frameworks diversos.
/minhaAplicacao/META-INF/context.xml Esse arquivo, que também está em um diretório não público, define algumas propriedades da aplicação/contexto, sendo que na arquitetura CORE, utilizamos para ligar a aplicação ao banco de dados que iremos utilizar.
*Na arquitetura CORE apenas os arquivos referentes a leiaute (CSS, Javascript, imagens, etc) ficam no diretório principal da aplicação. As páginas JSP ficam dentro de WEB-INF/jsp, que é um diretório não-público, possibilitando seu acesso apenas através de Actions, forçando assim que se siga corretamente o modelo MVC.
2. ARQUITETURA
Arquitetura baseada na divisão de responsabilidades em camadas, facilitando assim, a especialização do trabalho da equipe.
a) Bibliotecas e Ferramentas → Acesso ao Banco de Dados:
JPA; Hibernate; Core;
→ Controlador de Ações Mentawai;
→ Disponibilização dos Serviços Core;
→ Autenticação e Autorização:
Mentawai; Core;
→ Single Sign-On (Autenticação única e centralizada):
Core; → Auditoria: Log4J; Core; → Gerenciador de Configurações: Apache commons-configurator; VISUALIZAÇÃO
Exibe e captura dados do usuário. Páginas JSP.
AÇÕES
Validação e organização dos dados para chamada
dos serviços
SERVIÇOS
Regras de Negócio. Única camada que tem acesso
ao banco de dados
BEANS
Representa o banco de dados no modelo orientado a objetos. É o único objeto que transita
Core; → Gerenciador de Leiautes: Sitemesh; → Relatórios: JasperReports; iReport; → Paginação WEB: DisplayTable; → Controle de Versões: CVS; → IDE: Eclipse; → Scripts: Apache-Ant; Bash; b) Outros Recurso
→ Envio e armazenamento de mensagens eletrônicas;
→ Captcha (Evita que programas robôs preencham formulários); → Protocolo de Leitura de Email;
c) Principais Fluxos
3. BEANS
Classes no formato de JAVABEANS, ou seja, objetos sem lógica de negócio, que apenas armazenam dados, são utilizados para representar as tabelas do banco de dados. As classes, obrigatoriamente, precisam estar no pacote br.unesp.beans, onde cada classe é uma tabela, cada atributo um campo e cada objeto uma linha no banco de dados. Exemplo de uso:
@Entity
@Table(name = "curso")
public class Curso implements Serializable {
private static final long serialVersionUID = -6730719503656934127L; @Id
@SequenceGenerator(name = "SEQ", sequenceName = "seq_curso", allocationSize = 1) @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ")
@Column(name = "id", nullable = false) private Integer id;
@Column(name = "nome", nullable = false) private String nome;
@Column(name = "sigla", nullable = false) private String sigla;
@JoinColumn(name = "id_departamento", referencedColumnName = "id") @ManyToOne
private Departamento departamento; (…) gets e sets omitidos (…) }
4. AÇÕES
Ações são responsáveis por receber os dados vindos do cliente (ex: página jsp),
organizar esses dados, executar o método de negócio apropriado (objetos de serviço) e devolver a resposta para o cliente.
a) Configuração do Fluxo
Basicamente as ações executadas são configuradas através do mapeamento da URL de submissão de um formulário html enviado. Toda URL de submissão com o sufixo “.action” é considerada uma ação. Exemplo:
<form method="post" action="/curso.gravar.action"> <%-- Formulário --%>
</form>
O mapeamento do fluxo, ou seja, de onde veio a requisição e para onde vai a resposta, é realizado na própria classe da ação, através de anotações:
@ActionClass(prefix = "/curso")
public class CursoAction extends BaseAction { @Consequences(outputs = {
@ConsequenceOutput(result = SUCCESS, page = "/mensagem_ok.jsp"), @ConsequenceOutput(result = ERROR, page = "/mensagem_erro.jsp") }) public String gravar() {
(…) Código da ação (…) if (erro) return ERROR; return SUCCESS; } }
Dessa forma, ao enviar o formulário, o sistema irá executar o método gravar() da classe CursoAction e redirecionará após o término da execução com sucesso para a página mensagem_ok.jsp. ou no caso de execução com falha, para a página mensagem_erro.jsp.
No caso das duas condições (sucesso e erro) direcionarem para a mesma página podemos declarar apenas uma consequência, como abaixo:
@Consequences(outputs = @ConsequenceOutput(page = "/listagem.jsp"))
Os requisitos a serem atendidos pelas classes de ações são:
● O sufixo do nome da classe deve ser, preferivelmente, Action;
● Estar, preferivelmente, no pacote br.unesp.<nome_da_aplicação>.actions; ● A classe ActionsManager deve herdar br.unesp.web.AbstractActionsManager.
b) Validações de Dados
A validação nas ações serão a nível de campo, como, por exemplo, testando se o campo foi preeenchido, seu formato e tamanho, etc. E, em caso de não validado, uma mensagem de erro será exibida ao usuário.
Como nos serviços, a validação de dados serão feitas utilizando métodos da classe br.unesp.core.Log4jWrapper, conforme exemplo abaixo:
public String gravar() { try {
Log4jWrapper log = new Log4jWrapper(CursoAction.class, null); Curso curso = (Curso)session.getAttribute("curso");
curso.setNome(input.getStringValue("txt_nome")); curso.setSigla(input.getStringValue("txt_sigla"));
curso.setDataInicio(input.getDate("txt_data_inicio", "dd/MM/yyyy")); if (curso.getNome() == null)
throw new ServiceValidationException("Nome é um campo obrigatório"); academicoService.gravarCurso(curso);
}
catch (ServiceValidationException unespex) { addError(unespex.getMessage());
return ERROR; }
catch (Exception ex) {
addError(ConfigHelper.get().getString("error.general")); log.error(ConfigHelper.get().getString("error.general"), ex); return ERROR;
}
return SUCCESS; }
c) Tratamento de Erros
As ações irão capturar, caso necessário, as exceções do tipo br.unesp.exception.ServiceValidationException e exibir a mensagem nela contida para o usuário.
Deverão, obrigatoriamente, capturar exceções do tipo java.lang.Exception e exibir uma mensagem de erro genérica para o usuário.
Quando capturado uma exceção do tipo java.lang.Exception pela classe de ação, ela deve, obrigatoriamente, registrar no log a exceção em nível de error.
5. SERVIÇOS
Serviços são objetos que encapsulam toda a regra de negócio do sistema. São os únicos
objetos que tem acesso às informações do banco de dados.
a) Instanciação de Objetos de Serviço
Para que a classe sejam reconhecida como sendo de serviço, ela precisa obedecer a alguns requisitos como:
● Deve herdar da classe abstrata br.unesp.core.AbstractBasicService; ● Deve estar no pacote br.unesp.services;
● Ter o construtor sem modificador de visibilidade (public, protected ou private);
● Pode ou não receber como parâmetro no construtor um array da classe Object[] para ser usado nos métodos de negócio;
● O sufixo do nome da classe deve ser, preferivelmente, Service (ex: MatriculaService, DocumentoService, etc);
● Não devem manter estado, ou seja, não devem ter atributos de visibilidade public, que possam ser usados em outra classe a não ser ela mesma;
Como o construtor dessa classe não é público, objetos de serviço não podem ser instanciados com o comando new. Ele deve ser instanciado através de uma fábrica, conforme sintaxe
abaixo:
MatriculaService objetoService = (MatriculaService)ServicesFactory.
getInstance(MatriculaService.class, new Object[] { userLogin });
No exemplo acima, objetoService seria o objeto de serviço instanciado.
b) Auditoria e Validações de Negócio
Sendo a única camada com acesso ao banco de dados, os serviços são onde é possível alterar suas informações. Portanto, todo método de serviço que alterar dados no banco de dados deve registrar a operação.
A validação nas classes de serviço serão referentes a regras que exijam algum processamento (Ex: checagem de pré-requisitos de matrícula). A mensagem registrada será exibida para o usuário.
Tanto a auditoria quanto a validação de dados serão feitas utilizando métodos da classe br.unesp.core.Log4jWrapper, conforme exemplo abaixo:
public void gravarDisciplina(Disciplina disciplina) throws ServiceValidationException { Log4jWrapper log = new Log4jWrapper(ClasseService.class, null);
if (disciplina.getNome() == null || "".equals(disciplina.getNome())) {
5 log.warn("Nome é um campo obrigatório");
6 throw new ServiceValidationException("Nome é um campo obrigatório");
}
saveAndCommit(disciplina);
10 log.info("Gravado disciplina ID: " + disciplina.getNome());
Onde o objeto log é utilizado para registrar tanto a validação, nas linha 5 e 6 quanto a
auditoria na linha 10.
c) Tratamento de Erros
As classes de serviço não irão tratar nenhum tipo de exceção de sistema, como por exemplo, o banco de dados fora do ar. Os serviços sempre irão repassar para o nível acima (classes de ações).
No caso dos serviços terem que comunicar algum tipo de erro para o nível superior, ela deve disparar a exceção do tipo br.unesp.exception.ServiceValidationException passando o texto da mensagem de erro formatada como argumento da exceção, em nível de warning.
Como visto acima, no exemplo nas validações.
6. AUTORIZAÇÃO
A classe a ser mantida na sessão do usuário para autorização nas classes de ações é a classe br.unesp.beans.UserLoginWrapper.
Caso o sistema seja web e use como autenticação o filtro da classe br.unesp.web.SSOAuthorizationFilter de Single-Sign-On, automaticamente o objeto do tipo br.unesp.beans.UserLoginWrapper será incluído na sessão do usuário.
Para autorizar o usuário em uma classe de ação, ela deve implementar a interface org.mentawai.authorization.Authorizable e seu método public boolean authorize(String innerAction, Object user, List groups).
Exemplo:
public class CadastroCursoAction extends BaseAction implements Authorizable, Validatable { @SuppressWarnings("unchecked")
public boolean authorize(String innerAction, Object user, List groups) { if (user == null || groups == null)
return false; instanciarServicos((UserLoginWrapper)user); if (groups.indexOf(KGlobal.CATEGORIA_ADMINISTRADOR) != -1) return true; return false; } }
7. CONFIGURAÇÕES DE SISTEMA
As configurações de sistema podem estar no formato de arquivos de propriedades (.properties) ou em arquivos xml.
Obrigatoriamente, devem estar dentro do diretório config do diretório raiz das classes do sistema (em aplicações web, o diretório é /WEB-INF/classes/config).
Dentro do diretório config podemos ter outros subdiretórios com o nome da maquina e nome de domínio para conter arquivos de configuração. Nome de domínio é um subconjunto qualquer, passado como parâmetro pela aplicação.
Os arquivos de configurações seguirão uma ordem de prioridades conforme seus diretórios, onde prevalecerá sobre os demais da seguinte forma:
1) /config/<nome_da_máquina>/<nome_do_domínio>/* 2) /config/<nome_do_domínio>/*
3) /config/<nome_da_máquina>/* 4) /config/*
Para exemplificar, digamos que temos uma entrada em um arquivo de propriedades chamado email.properties com a seguinte linha:
# Arquivo email.properties host.smtp = localhost
Para acesso ao valor da chave, utilizamos no código fonte java:
// Código JAVA
ConfigHelper.get().getString("host.smtp");
Podemos passar parâmetros para substituição nas configurações, podendo assim gerar, por exemplo, mensagens em tempo de execução. Exemplo:
# Arquivo error.properties
error.required = O campo {0} é obrigatório para o cadastro {1}.
Para passar os parâmetros de substituição:
// Código JAVA
String[] valoresASubstituir = { "nome", "aluno de graduação" };
addError(ConfigHelper.getProperty("error.required", valoresASubstituir));
O valor retornado acima seria: "O campo nome é requerido para o cadastro de aluno de graduação".
8. PADRONIZAÇÃO DE CÓDIGO
a) Sufixos nos nomes de classes
● Para classes de serviço: Sufixo "Service". Ex: CommonService ● Para classes de ações: Sufixo "Action". Ex: PublicAction
● Para classes de exceções: Sufixo "Exception": Ex: ServiceException
b) Nomes de métodos de busca
● Métodos que buscam um objeto específico: Iniciar com "buscar". Ex: buscarEntidadePorId(int id)
● Métodos que filtram e trazem uma lista de objetos: Iniciar com "filtrar". Ex: filtrarEntidadePorNome(String nome)
● Métodos que listam todos objetos sem restrição: Iniciar com "listar". Ex: listarPaises()
c) Nomes de métodos de alteração no banco de dados
● Métodos que incluem e alteram dados: Iniciar com "gravar". Ex: gravarFuncionario(Funcionario funcionario)
● Métodos excluem dados. Iniciar com “excluir”. Ex: excluirFuncionario(int id).
9. IMPLANTAÇÃO
A implantação de um sistema será feito através do script bash cvs_download.sh na linha de comando de um sistema Linux, pré-configurado com o servidor de aplicações. Ele utiliza o repositório CVS para buscar o código do sistema. Para a compilação e checagem das configurações é utilizado o script bash build_java.sh junto com a biblioteca java apache-ant.