Anexo 15 - Arquitetura Referência

Propaganda
ANEXO 15
ARQUITETURA DE REFERÊNCIA
O CEPROFW é uma ferramenta que possui diversas funcionalidades desenvolvidas sobre a plataforma
Java EE 6 tendo como objetivo prover um fluxo padrão para o desenvolvimento de aplicações.
O CEPRO-FW tem como base a plataforma Java EE 6, utilizando como container oficial o JBoss AS 6. O
JBoss provê uma série de serviços que são estendidos e abstraídos pelo framework, de forma a padronizar
e facilitar o desenvolvimento de aplicações Java EE 6. Como parte principal da camada Web, o framework
utiliza o JavaServer Faces na versão 2.1, integrado ainda ao conjunto de componentes PrimeFaces. Para
javascript é feito uso intenso do jQuery.
Na camada de serviço as regras de negócio são implementadas como EJBs, o que permite o uso do
controle transacional e contexto de segurança do próprio container, utilizando JPA para o acesso a dados.
O CEPRO-FW provê ainda o módulo CEPRO-FW Commmon que contém uma série de classes utilitárias
úteis no desenvolvimento de aplicações Java em geral.
Organização da Arquitetura:
Como mostrado na figura acima, o framework utiliza o CDI como framework de injeção de
dependências, servindo como "cola" entre todas as camadas e bibliotecas utilizadas.
Diagramas de Classes:
Página 1 de 15
Application Layers (FOWLER):
As aplicações construídas com o framework serão construídas com camadas lógicas com o objetivo de
aumentar a manutenibilidade, o reuso e a escalabilidade. Camadas:
1. Data source layer ou camada de acesso a dados
2. Domain model ou camada de lógica de negócio
3. Service layer ou façade
4. View ou Apresentação
Model View Controller (FOWLER):
Promove a separação de responsabilidades na construção da interface com usuário garantindo
manutenibilidade e reuso de componentes de interface.
Page Controller (FOWLER), View Helper (CORE):
Ambos os padrões são semelhantes e podem ser aplicados como uma extensão do padrão model view
controller. Como será utilizado JSF, existirá um managed bean para cada página, que realiza o papel de
page controller.
Service Layer (FOWLER), Session Façade (CORE), Façade (GAMMA):
Estes padrões são aplicados nas classes da camada facade. Está classe tem como objetivo de simplificar
a interface de negócio, expondo uma API simplificada para a camada de apresentação.
Uma característica importante da camada façade é a ausência de manutenção de estado, facilitando
sua exposição como um webservice, se for necessário.
Página 2 de 15
Domain Model (FOWLER):
Este padrão determina que todas as regras de negócios sejam implementadas em classes que não
sejam acopladas com mecanismos de persistência ou de apresentação ao usuário. As classes de negócio
serão implementadas conforme as diretivas deste padrão de Projeto
Data Access Objects:
Os Data Access Objects (DAO) são responsáveis por encapsular e abstrair o acesso a dados da
aplicação. Uma aplicação deve conter um DAO para cada entidade ou grupo de entidades fortemente
relacionadas, de forma a cobrir todo o modelo da mesma. Classes que executam regras de negócio devem
obter os DAOs por injeção de dependência, usando a infraestrutura já disponibilizada pelo container (CDI).
O CEPRO-FW provê uma classe abstrata chamada AbstractDAO que provê uma série de métodos
comuns em todos os DAOs. Esta classe deve ser estendida na aplicação para gerar um BaseDAO para
prover uma instância de Entity Manager, do qual todos os DAOs da aplicação devem estender.
Visão Conceitual (modelo conceitual):
Visão Lógica (modelo lógico):
Página 3 de 15
Componentes:

Plugin Gerador de Código

Componentes de Infraestrutura

Componentes de Negócio

Componentes para Web

Componente para Paginação sob Demanda

Componente DynamicFilter

Componente CKEditor

Componente MailAsync

Componente PersistenceManager

Componente Menu

Componente Menu Security

Componente Agendador de Tarefas

Componente para Certificação Digital

Componente EntityConverter

Componentes de Segurança

Componentes de Cadastro
Frameworks e Tecnologias:
Página 4 de 15

Enterprise Java Beans (EJB 3): Especificação desenvolvida com intuito de prover um modo padrão
para implementação de componentes de negócio, tipicamente encontrada em aplicações
enterprise. Integrada com diversas tecnologias o framework gerencia integridade de dados,
segurança, controle transacional, e de persistência de um modo padrão.

JavaServer Faces (JSF 2.1): JSF é um framework web, criado para simplificar o desenvolvimento e
integração de aplicações web. Atualmente é considerado um padrão da indústria, com suporte em
todos os Application Server Java EE desde a versão 5.

Spring Framework: Framework que provê uma série de funcionalidades necessárias para a maioria
dos aplicativos Java tais como Inversão de Controle, Gerenciamento de Transações, Processamento
Assíncrono, Processamento em Massa, Programação orientada a aspecto.

PrimeFaces 2: Suíte de componentes para JSF 2, contendo mais de 100 componentes ricos com
suporte a tecnologia web como AJAX, CSS 2 e 3, possibilidade de criação de temas, etc.

Java Persistence API (JPA 2): API para gerenciamento de persistência. Gerencia a leitura e escrita de
dados relacionais, criando uma camada de abstração acima do banco de dados relacional,
diminuindo a complexidade de gerenciamento de cache, pool de conexões, transações, além de
fazer com que a aplicação possa ser independente do banco de dados configurado.

Dependency Injection for Java (JSR 330): Criado para padronizar as annotations necessárias para a
implementação de Dependency Injection em aplicativos java, o que permite menor acoplamento
entre as camadas, diminuindo consideravelmente a dependência entre as mesmas.

Bean Validation(JSR 330): Framework para validação de Beans (entidades de negócio, objetos Java,
etc). Criado para padronizar e simplificar a validação de dados, cuja fonte pode ser integração
entre sistemas (Webservices), dados entrados pelo usuário via web, etc.
Paginação Sob Demanda:
Para implementar a paginação sob demanda utilizando o LazyObjectDataModel o desenvolvedor deve
importar o LazyObjectDataModel e construir o objeto passando o Model que vai ser utilizado como
Generic, passar o service que deve estender o PaginableService e um criteria que será passado do bean até
o service como Objeto.
Exemplo de utilização do LazyObjectDataModel:
LazyObjectDataModel<TesteLazy>lazyList
LazyObjectDataModel<TesteLazy>(testeLazyService,criteria);
=
new
Como Funciona o LazyObjectDataModel:
Quando o objeto é criado o PaginableService e o criteria são carregados, e em cada mudança de página
também é chamado o metodoload.
O no método load é passado a posição da pagina, a quantidade exibida por pagina, a coluna que será
ordenada e a ordem, de acordo com essas informações são montadas a consulta para contar os registros
totais e outra consulta que retorna apenas os registros que serão mostrados na tela.
Página 5 de 15
Como Funciona o PaginableService:
O PaginableService é uma classe Abstrata que estende o BaseService adicionando dois métodos
essenciais para a construção de um LazyObjectDataModel, que são:

FindAllByCriteriaPaginacao: Recebe como parâmetro a posição da pagina, a quantidade exibida
por pagina, o criteria, a coluna que será ordenada e a ordem.Retorna uma lista genérica.

CountAllByCriteria: Recebe como parâmetro a posição da pagina, a quantidade exibida por pagina,
o criteria, a coluna que será ordenada e a ordem.Retorna um Long.
Filtro Dinâmico:
O objetivo deste texto é apresentar como é realizado a instalação dos filtros dinâmicos. Um filtro
dinâmico é um componente visual destinado a permitir selecionar vários campos como critério de filtro. A
utilização dos filtros dinâmicos é realizada em duas etapas.
1 – ETAPA:
Consiste em anotar os campos do objetosCriteria, com a anota @FilterFieldOption, tais campos após
anotados passarão a fazer parte da listagem de possíveis campos de filtragem.
publicclassTesteLazyCriteriaimplementsDynamicQuery {
private Date dataRealizacao;
private Date dataVencimento;
private String local;
private String acao = "lista";
private String sortField;
private String sortOrder;
private List<FilterField>dynamicFilter;
@FilterFieldOption(label = "Sigla", property = "sigTesteLazy",
control=ControlType.COMBOBOX, valuesKeys="1, 2, 3", valuesString="BA, RJ,
CE", value="BA", validator=SiglaValidator.class)
private String sigla;
@FilterFieldOption(label = "Descrição", property = "descTesteLazy")
private String descricao;
2 – ETAPA:
Consiste em adicionar a página XHTML o código necessário para geração do Filtro.
<p:panelid="filtroPanel"toggleable="true"toggleSpeed="300"
closeSpeed="2000"widgetVar="widgetFiltroPanel"
styleClass="ui-kfe-panel-filtro">
<h:panelGridcolumns="2"styleClass="ui-kfe-component-panel">
<h:selectOneMenuvalue="#{TesteLazyBean.filterField}">
<f:selectItemsvalue="#{TesteLazyBean.filterFields}"/>
</h:selectOneMenu>
<p:commandButtonvalue="Adicionar"
actionListener="#{TesteLazyBean.adicionar}"
update="filtros, tabelaCampos"/>
Página 6 de 15
<h:dataTableid="tabelaCampos"
value="#{TesteLazyBean.criteria.dynamicFilter}"var="campo">
<p:columnheaderText="Campo">
<h:outputTextvalue="#{campo.field}"/>
</p:column>
<p:columnheaderText="Condição">
<h:selectOneMenuvalue="#{campo.expression}">
<f:selectItemsvalue="#{TesteLazyBean.expressions}"/>
</h:selectOneMenu>
</p:column>
<p:columnheaderText="Campo">
<h:inputTextvalue="#{campo.value}"
rendered="#{campo.controleq
'textbox'}"/>
<h:selectOneMenuvalue="#{campo.value}"
rendered="#{campo.controleq
'combobox'}">
<f:selectItemsvalue="#{campo.valuesString}"/>
</h:selectOneMenu>
</p:column>
<p:columnheaderText=""id="remover">
<h:commandLinkvalue="Remover">
<p:collectorvalue="#{campo}"removeFrom="#{TesteLazyBean.criteria.dynamicFilter}"/>
</h:commandLink>
</p:column>
</h:dataTable>
</h:panelGrid>
</p:panel>
Página 7 de 15
Ceprofw – CKEditor:
O Ceprofw-CKEditor é um componente que fornece um editor rico dentro da plataforma Ceprofw, este
editor foi estendido da biblioteca Primefaces-Extension-CKEditor e foram adicionadas funcionalidades para
atender às necessidades do CEPROMAT. Para usar o CKEditor basta realizar as seguintes configurações
básicas no arquivo .XHTML:
<ceprofw:ckEditor
id="editor1"
value="#{editorBean.htmlValue}"
pathFile="img-ckeditor"
imageLocalType="disk"
fileUploadLimit="1000000"
idDoc="#{editorBean.idDocumento}">
<p:ajax event="save" listener="#{editorBean.saveListener}"
update="form"/>
</ceprofw:ckEditor>
Onde:

id – é o id do componente;

value – propriedade value padrão;

pathFile – diretório aonde serão armazenadas as imagens no servidor;

imageLocalType – nesta propriedade deverá ser informado os valores: disk ou db. Onde, disk será
para guardar as imagens no disco do servidor dentro de pathFile ou db que irá direcionar as
imagens para o banco de dados;

fileUploadLimit – tamanho máximo do arquivo de imagem;

idDoc – valor da propriedade id do objeto aonde será guardado o texto do editor. Este id será um
subtiretório de pathFile. Ex.: img-ckeditor/1020. Ou seja, para cada idDoc um subdiretório será
criado dentro do caminho informado em pathFile.
Observação: Neste caso, para que as imagens sejam gravadas corretamente no disco, faz-se necessário
que o objeto que possui o idDoc já esteja persistido no banco de dados.
Exemplo simples de utilização do Ceprofw-CKEditor:
Guardando as Imagens no disco.
//Criando o ManegedBean
publicclassEditorBeanextendsBaseBean {
@EJB
privateDocumentoServicedocumentoService;
private Documento doc = null;
private Long idDocumento;
private String descricao;
private String htmlValue;
private String textValue;
private Long idLocate = 0l;
privatefinal String PATH_FILE = "img-ckeditor";
//Getters e Setters omitidos
publicString novo(){
//Regra para limpar campos
returnnull;
Página 8 de 15
}
public String pesquisar(){
doc = documentoService.findId(idLocate);
if (doc!=null){
idDocumento = doc.getId();
textValue = doc.getValorTexto();
}
returnnull;
}
public String delete(){
String path = FacesContext.getCurrentInstance().
getExternalContext().getRealPath("")+
"\\" + PATH_FILE + "\\" + doc.getId();
if (documentoService.delete(doc))
deleteDir(path);
returnnull;
}
public String salvar(){
if (idDocumento==null)
doc = newDocumento();
else
doc = documentoService.findId(idDocumento);
doc.setDescricao(descricao);
doc.setValorHtml(htmlValue);
documentoService.persist(doc);
idDocumento = doc.getId();
returnnull;
}
public void saveListener() {
salvar();
}
}
Página 9 de 15
Guardando as imagens no banco de dados:
Para guardar as imagens no banco de dados deve-se criar uma classe de serviço implementando a
interface IAnexoService do Ceprofw. Em seguida, implementar os métodos save e findId. No arquivo
.XHTML informar o nome completo da classe criada para a propriedade classService do CKEditor. Veja a
baixo um exemplo de utilização; Classe de serviço:
importbr.gov.mt.cepromat.ceprofw.core.service.editor.IAnexoService;
publicclassUserAnexoServiceimplementsIAnexoService{
privateIAnexoServiceanexoService;
privatevoidserviceLookup() throwsNamingException{
InitialContextctxIni = newInitialContext();
anexoService = (IAnexoService) ctxIni.lookup("java:global/exemploapp/exemplo-web-0.0.1-SNAPSHOT/AnexoService");
}
@Override
public String save(byte[] image, String fileName, Long idDocumento) {
String id_imagem=null;
try {
serviceLookup();
id_imagem = anexoService.save(image, fileName, idDocumento);
} catch (NamingException e) {
e.printStackTrace();
}
returnid_imagem;
}
@Override
publicbyte[] findId(Long id) {
byte[] bytes = null;
try {
serviceLookup();
bytes = anexoService.findId(id);
} catch (NamingException e) {
e.printStackTrace();
}
return bytes;
}
}
Configurando as propriedades no arquivo .XHTML:
Página 10 de 15
<ceprofw:ckEditor
id="editor1"
value="#{editorBean.htmlValue}"
imageLocalType="db"
fileUploadLimit="1000000"
classService="br.gov.mt.cepromat.exemplo.web.service.UserAnexoService"
idDoc="#{editorBean.idDocumento}"/>
Observação: O Ceprofw guardará as imagens enviadas dentro do diretório de backup tmp-ceprofw-img
com a extensão .TMP.
Configurando Vários Editores na tela:
Para que a aplicação possa utilizar mais de um editor na tela deve-se criar uma classe de serviço
(IAnexoService) para cada editor. Como no exemplo acima, esta classe será responsável em gerenciar as
imagens no banco de dados.
<h:panelGridcolumns="1">
<ceprofw:ckEditor
id="editor1"
width="0"
value="#{editorBean.htmlValue}"
imageLocalType="db"
fileUploadLimit="1000000"
classService="br.gov.mt.cepromat.exemplo.web.service.UserAnexoService"
idDoc="#{editorBean.idDocumento}">
<p:ajax event="save" listener="#{editorBean.saveListener}"
update="form"/>
</ceprofw:ckEditor>
<ceprofw:ckEditor
id="editor2"
width="0"
interfaceColor="#6495ED"
value="#{editorBean.htmlProcessoValue}"
imageLocalType="db"
fileUploadLimit="1000000"
classService="br.gov.mt.cepromat.exemplo.web.service.UserAnexo2Service"
idDoc="#{editorBean.idDocumento}">
<p:ajax event="save" listener="#{editorBean.saveListener}"
update="form"/>
</ceprofw:ckEditor>
</h:panelGrid>
Observação: caso a propriedade idDoc for diferente para cada editor, faz-se necessária a mudança do
arquivo de configuração do CKEditor.
Convertendo o Texto formato Html para Texto simples:
Para converter o texto Html para o formato texto simples basta utilizar a classe Html2Text do Ceprofw,
esta classe possui um método estático html2text que recebe como parâmetro uma string contendo o texto
em formatoHtml e retorna uma string com um texto sem as tags HTML. Ex.:
Página 11 de 15
Importbr.gov.mt.cepromat.ceprofw.web.jsf.component.editor.Html2Text;
…
Html2Text.html2text(textoHtml);
…
Ceprofw –EntityConverter:
O EntityConverter é um conversor genérico para entidades JPA, seguindo sua especificação. A
conversão não limita apenas a essas entidades, sendo possível converter outros objetos, onde seja criado
algum identificador e seu atributo/método seja anotado com @ConverterId. É importante destacar que
para seu funcionamento a classe deve possuir seu devido método equals sendo feito pelo identificador da
entidade. Abaixo um exemplo de sua utilização:
<h:selectOneMenu value="#{bean.group}" converter="entityConverter" >
<f:selectItems value="#{bean.groups}" var="group" itemLabel="#{group.description}" />
</h:selectOneMenu>
O funcionamento desse conversor se dá da seguinte maneira, cada objeto da lista é adicionado ao
ViewMap do JSF, com isso ao submeter a página o objeto é recuperado desse Map. Isso torna
desnecessário consultas extras no banco de dados ou a criação de um conversor para cada entidade
Configurando o JBoss para Usar o JAAS
Arquivo de Configuração: Para configurar API JAAS no jboss o desenvolvedor precisa acessar o arquivo
de configuração (standalone.xml/domain.xml) e adicionar em <security-domains> a seguinte
parametrização.
. . .
<security-domain name="jaasMenu" cache-type="default">
<authentication>
<login-module code="Database" flag="required">
<module-option name="dsJndiName"
value="java:jboss/datasources/exemplo_local"/>
<module-option name="principalsQuery" value="select pws from user
where name=?"/>
<module-option name="rolesQuery" value="select ur.name, 'Roles'
from user_role ur inner join user_user_role uur on (ur.id = uur.roles_id)
inner join user u on (u.id = uur.user_id) where u.name =?"/>
<module-option name="unauthenticatedIdentity" value="guest"/>
</login-module>
</authentication>
</security-domain>
. . .



dsJndiName – Deve ser definido o banco de dados padrão para acesso aos dados de usuário, senha
e
regras
de
acesso
neste
exemplo
foi
utilizado
o
endereço
JNDI
“java:jboss/datasources/exemplo_local”.
principalsQuery – Neste parâmetro deve ser definido a query principal para validar a senha do
usuário.
rolesQuery – Esta query serve para que o JAAS localize as regras de acesso para o usuário.
Página 12 de 15

Este é um exemplo simples com os parâmetros básicos de autenticação. Existem outros parâmetros
como:
 hashAlgorithm: define o algoritmo de criptografia da senha;
 hashEncoding: formato do texto da senha.
Configurar jboss-web.xml:
Adicionar um arquivo de configuração do JBoss (jboss-web.xml) copiar para o mesmo local do web.xml,
com o conteúdo abaixo:
<?xml version="1.0" encoding="UTF-8"?>
<jboss-web>
<security-domain>java:/jaas/jaasMenu</security-domain>
</jboss-web>
Configurar web.xml:
<!-- Protected Areas -->
<security-constraint>
<web-resource-collection>
<web-resource-name>Páginas protegidas</web-resource-name>
<url-pattern>/resources/pages/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>ADM</role-name>
<role-name>USER</role-name>
</auth-constraint>
</security-constraint>
<!-- Validation By Form -->
<login-config>
<auth-method>FORM</auth-method>
<form-login-config>
<form-login-page>/exemplo/login</form-login-page>
<form-error-page>/resources/pages/common/error.jsf</form-error-page>
</form-login-config>
</login-config>
<!-- Allowed Roles -->
<security-role>
<role-name>ADM</role-name>
</security-role>
<security-role>
<role-name>USER</role-name>
</security-role>
Tabelas no banco de dados:
CREATE TABLE tb_teste.user
(
id bigint NOT NULL,
"name" character varying(30),
pws character varying(30),
CONSTRAINT user_pkey PRIMARY KEY (id)
Página 13 de 15
);
create table tb_teste.role(
id bigint primary key not null,
name varchar(30) not null
);
CREATE TABLE tb_teste.user_role
(
user_id bigint NOT NULL,
role_id bigint NOT NULL
)
ALTER TABLE user_role ADD PRIMARY KEY(role_id, user_id);
ALTER TABLE user_role ADD FOREIGN KEY (user_id) REFERENCES user(id);
ALTER TABLE user_role ADD FOREIGN KEY (role_id) REFERENCES role(id);
Inserindo Usuário:
INSERT INTO "user"(id, pws, "name")
VALUES(1,'1','cepro');
Inserindo Regras:
Com a tabela de regras criada, inserir dados de exemplo.
INSERT INTO role(id,name) VALUES (1,'USR');
INSERT INTO role(id,name) VALUES (2, 'ADM');
Inserindo Regras do Usuário:
INSERT INTO user_role(user_id,role_id) VALUES(1,1)
Formulário de Login:
Este é um exemplo simples de um formulário de login, deve-se observar que a action do form
j_security_check é padrão da API JAAS, assim como o nome dos campos: j_username e j_password.
<form method="post" action="j_security_check">
<h:panelGrid columns="2">
<h:outputLabel for="j_username" value="Username" />
<input type="text" id="j_username" name="j_username" />
<h:outputLabel for="j_password" value="Password" />
<input type="password" id="j_password" name="j_password" />
<input type="submit" name="submit" value="Login" />
</h:panelGrid>
</form>
Arquitetura Específica da Secretaria de Estado de Segurança Pública:
Características Arquiteturais:
1. A utilização da especificação JAVA EE 6 (EJB, JSF, JPA,CDI);
2. Controle transacional por parte do servidor de aplicação (Especificação EJB Java EE 6);
3. Servidor de Aplicação Weblogic 12.1.3 (Fornece as bibliotecas para suporte ao JEE 6);
4. framework SHIRO 1.3.2 para segurança de acesso;
5. framework DeltaSpike 1.5.0 para suporte à especificação CDI;
Página 14 de 15
6. Archetype Maven 1.0 visando uma padronização estrutural dos novos projetos.
Referências:
http://docs.huihoo.com/jboss/portal/2.6/reference-guide/html/authentication.html
http://amatya.net/blog/implementing-security-with-jaas-in-jboss-as-7/
http://www.j3ltd.com/articles/jaas/Jaas1.htm
Página 15 de 15
Download