Mostrando postagens com marcador ADF. Mostrar todas as postagens
Mostrando postagens com marcador ADF. Mostrar todas as postagens

segunda-feira, 17 de novembro de 2008

ADF BC: Como inativar um registro ao invés de deletar

Olá novamente pessoal!

Hoje vamos fazer um rápido HOW-TO baseado em um requisito bastante comum. Por várias vezes, os clientes solicitam sistemas que não permitem a deleção de registros, para fins de histórico. Ao invés disso, cria-se na tabela um campo STATUS, que pode levar um flag ATIVO (por exemplo, 'A') ou INATIVO ('I'). Sabemos que o BC tem uma ação padrão chamada "Delete" que remove o registro do RowSet do View Object e, ao efetuar commit(), emite uma instrução DELETE ao banco de dados. E agora?
Para solucionar este problema, vamos utilizar a orientação a objetos do Java e estender a implementação da Entidade, sobrescrevendo os métodos responsáveis pela remoção e pela execução do DML. Dividiremos essa tarefa em duas partes:

PARTE 1: COMO ALTERAR O STATUS DO REGISTRO AO INVÉS DE REMOVER?
Para alcançar este primeiro objetivo, sobrescrevemos o método remove() da classe de implementação da entidade. Por exemplo, supondo que nossa entidade chame EmployeeEO e que existe um campo chamado STATUS dentro dessa entidade, teremos uma classe chamada EmployeeEOImpl onde iremos criar o seguinte método, sobrescrevendo da superclasse:


public void remove() {
// Chamada nova: setar o valor do status para 'I'
this.setStatus("I");

// Chamada original, comentada
// super.remove();
}


Com isso, ao invés de remover a linha do RowSet, ele irá somente alterar o status para "I". Porém, imaginem que precisemos manter a chamada de super.remove() no método para que, ao inativar o registro, ele suma da tela do usuário. Se isso for verdade, temos de achar alguma maneira de dizer ao BC que não é necessário um DELETE, mas sim um UPDATE. Aí vem a parte 2...

PARTE 2: ALTERANDO A LÓGICA DE DML DO ENTITY OBJECT
Na mesma classe de implementação da entidade, temos um método chamado doDML(int operation, TransactionEvent e). Este método é responsável por disparar os comandos DML no banco de dados, portanto vamos desenvolver um "gancho" que intercepta essa chamada e altera a operação desejada de DELETE para UPDATE, sobrescrevendo o método como abaixo:

public void doDML(int operation, TransactionEvent e) {
//O parâmetro "operation" indica a operação desejada
//Pode ser DML_UPDATE, DML_DELETE, DML_INSERT...
//A nossa ação é verificar se é um DML_DELETE, e se for, trocar para DML_UPDATE
if (operation == DML_DELETE) {
operation = DML_UPDATE;
}

// Ao chamar a superclasse, vai "enganá-la", emitindo um UPDATE!
super.doDML(operation, e);
}


Com isso, você pode usar a operação "Delete" do application module normalmente, que a entidade irá se comportar da maneira desejada. Pode-se inclusive chamar row.remove() em uma linha do View Object programaticamente que o comportamento está garantido.

Bom ADF para vocês! Até Mais!

sábado, 1 de novembro de 2008

ADF BC: Usando History Columns sem JAAS

Olá pessoal!

Neste post vou chamar a atenção para um artifício extremamente útil durante a programação ADF BC. Encontrei esta solução em um artigo neste link abaixo, que depois apliquei e testei em projetos: http://my.opera.com/dominionspy/blog/show.dml/575983

Em resumo: o ADF BC possui um mecanismo muito prático de rastreamento de registro por usuário, que é chamado de History Columns. Imaginem que temos um campo, CREATED_BY, na nossa tabela no qual queremos gravar o nome do usuário que criou o registro. O ADF BC permite que marquemos este campo como History Column ao editarmos o Entity Object e visualizarmos as propriedades do atributo CreatedBy, mapeado para essa coluna. Ao marcarmos este campo como History Column, também selecionamos o tipo de histórico para "Created By" para que automaticamente o BC pegue o usuário logado e grave-o nessa coluna durante a criação, sem nenhuma intervenção do programador. Simples, não?

Essa funcionalidade tem um porém: o BC só consegue pegar o usuário logado nativamente se você estiver usando a segurança declarativa, via WEB.XML (as tags por exemplo) e JAAS. Sabemos, no entanto, que em muitos dos nossos projetos o uso do JAAS é impossível, devido a limitações do framework (por exemplo, o JAAS só nos permite ter os dados de Usuário e Senha, nada mais) ou então de limitações do projeto, por já haver componentes de segurança feitos em outra tecnologia, por exemplo, Http Filters. Felizmente, uma simples mudança pode permitir que utilizemos esse outro método de autenticação sem perder as History Columns.

Funciona assim: o BC, para buscar o usuário logado, utiliza o método getRemoteUser() da Request HTTP, ou seja, o usuário que é populado pelo JAAS ao autenticar. Porém, existe um objeto chamado HttpServletRequestWrapper que permite que "embalemos" uma request original em um objeto customizado e passemos adiante através de um Filtro por exemplo, sobrescrevendo o método getRemoteUser() original e retornando nosso próprio usuário. Para isso, siga os passos adiante, que estão listados inclusive no link citado no início da página:

1) Crie um objeto que implemente a interface java.security.Principal, é o objeto que vai guardar os dados de usuário. Tem dois métodos: getName() e getRole(). Exemplo:

import java.security.Principal;

public class AuthUserPrincipal implements Principal {
private String username;
private int role;

public AuthUserPrincipal(String _username, int _role) {
this.username = _username;
this.role = _role;
}

public String getName() {
return username;
}

public int getRole() {
return role;
}
}


2) Crie uma classe que estenda javax.servlet.http.HttpServletRequestWrapper. Esta classe deve conter um construtor que permita informar o nome de usuário, e sobrescrever os métodos isUserInRole() e getRemoteUser. Exemplo:

import java.security.Principal;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

public class AuthRequestWrapper extends HttpServletRequestWrapper {
private AuthUserPrincipal principal;

public AuthRequestWrapper(HttpServletRequest request, String usuario, String role)
super(request);
this.principal = new AuthUserPrincipal(usuario, role);
}

public boolean isUserInRole(String string) {
return String.valueOf(principal.getRole()).equals(string);
}

public String getRemoteUser() {
return principal.getName();
}

public Principal getUserPrincipal() {
return principal;
}
}


3) Crie um filtro Http que "embale" o HttpServletRequest que recebe de parâmetro no seu HttpServletRequestWrapper. Por exemplo, supondo que seu filtro de autenticação colocou o nome do usuário e role na sessão Http:

public class BCAuthFilter extends javax.servlet.Filter {
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)req;
String user = request.getSession().getAttribute("user"); // Usuario
String role = request.getSession().getAttribute("role"); // Role

AuthRequestWrapper wrap = new AuthRequestWrapper(request, user, role);
chain.doFilter(wrap, resp);
}
}


4) Configure este filtro no seu Web.xml. IMPORTANTE: Você deve configurar este filtro antes dos filtros adfBindings e adfFaces, mas DEPOIS do seu filtro de autenticação:


BCAuthFilter
com.custom.BCAuthFilter


BCAuthFilter
/*



Desta maneira o seu aplicativo irá se logar através do filtro de autenticação; em seguida, o seu BCAuthFilter irá sobrescrever esses dados no Request, para que depois o ADFBindingFilter consiga recuperar esse dado em sua inicialização, através do request.getRemoteUser() (que na verdade executará o metodo sobrescrito do seu Wrapper).

Abraços!

sexta-feira, 29 de agosto de 2008

ADF BC: Configurando Application Modules para Performance e Escalabilidade: Parte 1

Oi pessoal!

Hoje a dica é sobre Application Module Configuration. Como vocês sabem, toda a camada de fachada do ADF BC é baseada nos Application Modules. Eles são responsáveis por controlar os acessos aos Data Sources, manter o controle transacional, instanciar os View Objects (e por consequência, os Entity Objects e suas queries) e controlar o fluxo da aplicação como um todo. Portanto, a correta configuração dos parâmetros dos AMs é fundamental para o bom desempenho e estabilidade da aplicação ADF como um todo.
Podemos acessar as configurações dos application modules clicando com o botão direito sobre eles no JDeveloper e selecionando o item "Configurations". Podemos por exemplo criar mais de um configuration, um Local (para uso com o Connection JDBC local) e um Remoto (Para uso dentro do App Server usando um Data Source).
Vamos hoje tratar portanto de um dos principais aspectos do ajuste de configurações: Pooling.
Assim como os Data Sources no Servidor J2EE são responsáveis por manter um pool de conexões de banco para melhorar a performance do acesso a dados, o chamado Connection Pooling, os Application Modules no ADF Runtime são responsáveis por manter um pool de AMs para servir mais rapidamente as aplicações ADF, chamado de AM Pooling. E da mesma maneira que os pools de conexão, podemos "tunar" a performance diminuindo o tempo que o runtime mantém uma instância do Application Module no ar ou aumentando o número de AM instances em memória para aguentar uma maior carga de usuários.
Para fazê-lo, selecionamos a configuração desejada dentro das Configurations e clicamos em "Edit", navegando para a aba "Pooling and Scalability". Nesta aba, temos a seção "Application Pool", onde podemos definir:
1) Initial Pool Size: Qual o tamanho inicial do meu pool de instâncias AM. Se colocarmos um valor muito baixo, cada usuário que se conectar demandará a instanciação de um AM, e por consequência, uma solicitação de conexão ao Data Source. Porém, se for muito alto, podemos estar esbanjando memória do servidor.
2) Maximum Pool Size: Qual o maior tamanho possível do pool. Segue a mesma lógica do Initial Pool Size, mas tem o efeito reverso.
3) Minimum Available Size: Número mínimo de instâncias que devem estar DISPONÍVEIS para uso.

Como o processo de instanciação é bem intensivo em uso de recursos, devemos planejar estes parâmetros levando em consideração o número de usuários logados ao mesmo tempo na aplicação. Para uma aplicação que, por exemplo, tenha no mínimo 2 usuários conectados a qualquer momento, seria interessante colocar o parâmetro Initial Pool Size como 2. O estudo destes parâmetros pode fazer a diferença na experiência do usuário.

Abraços!

segunda-feira, 7 de julho de 2008

Estratégia: Como modernizar aplicações em Forms para SOA

Olá pessoal!

Post rápido para vocês: Segue um link muito interessante da Oracle sobre estratégias de modernização de aplicações Forms, que mostra como migrar e/ou modernizar aplicações em forms utilizando tecnologias SOA como o ADF e o BPEL:

http://otn.oracle.com/goto/formsmodernize

Abraços!
Thiago