domingo, 8 de junho de 2008

Mudando a mensagem de erro para validação de Primary Key - ADF BC

Oi Pessoal,

Um dos grandes empecilhos do ADF BC é o seu conjunto de mensagens de erro extremamente técnicas, mesmo para os casos mais triviais. Um destes exemplos é o caso da validação de chave primária, que ocorre quando um ou mais atributos do Entity Object são marcados como "Primary Key". Neste caso, ao tentar inserir um registro com a mesma chave primária em um View Object baseado nessa entidade é exibido o erro:

Muitos Objetos correspondem à chave primária oracle.jbo.Key[valordaChave].

Um artifício pouco documentado da release 10.1.3 para resolver este problema é o uso da validação de entidade "UniquePKValidationBean". Esta é uma Entity Constraint que nos permite substituir a mensagem de erro a exibir caso a validação de PK falhe. Seguem dois passos simples para implementá-la:

(Contexto: Você tem um Entity Object chamado EmployeeEO baseado na tabela SCOTT.EMP cuja chave primária é o campo EMPNO, mapeado para o atributo EmpNo que já está marcado como Primary Key)

1) Entre no Configurador da entidade EmployeeEO clicando duas vezes sobre ela, e selecione a aba Validation. Então, selecione a primeira entrada do painel do lado direito, que representa a entidade inteira (EmployeeEO) e clique em "New..."


2) Selecione o validador "UniqueKey Validator" no drop-down. Perceba que ele só nos permite entrar com a mensagem de erro nova, já que esta validação funciona para todos os atributos que estiverem marcados como Primary Key (portanto, não precisamos dizê-lo o que fazer, ele já sabe validar esta unicidade).


Pronto! ao testar novamente você notará que o erro técnico foi substituído pelo que você especificou.

Algumas dicas extras:
1) Para internacionalizar a mensagem, lembre-se que todas as mensagens que são inseridas nos validadores de entidade são gravadas em uma classe separada chamada de Message Bundle, da mesma forma que os labels de atributo, onde esta mensagem do UniqueKey especificamente é gravada com o código "_Rule_0". Para mais informações sobre isso, favor consultar o manual do ADF BC na seção
6.5 Defining Attribute Control Hints

2) Para os que usam JSF com um PageLifecycle customizado, certifiquem-se que o tipo de exceção que o BC atira neste caso (RowValException) está devidamente tratado. Um exemplo disso é o PageLifecycle que vem junto com o tutorial da Oracle (SRDEMO). Neste caso, o ciclo customiza o mecanismo de tratamento de erros do JSF tratando as mensagens de erro do BC mais comuns, porém esquece completamente da RowValException. Para contornar a situação no caso do SRDEMO, vá para a classe SrDemoPageLifecycle e localize dentro do método processException() o seguinte condicional:

if (ex instanceof AttrValException) {}

Adicione um desvio ao final deste if da seguinte forma:

else if (ex instanceof RowValException && ex.getErrorCode().endsWith("Rule_0")) { globalErrs.add(ex.getLocalizedMessage(locale)); }

Isso irá considerar todas as RowValException cujo código termine com "Rule_0", o que é exatamente o caso do UniqueKey Validator.

Até mais pessoal! Feliz programação ADF pra vocês =)

sexta-feira, 6 de junho de 2008

Eliminando o registro corrente de um SelectOneChoice

Galera desculpa pela demora nos posts.

Hoje é uma dica bastante interessante para a galera que desenvolve aplicativos com muitas ligações.
Em nosso cenário teremos uma página de cadastro, aonde o VO base irá conter uma ligação apontando para a mesma tabela base.
/* Tabela Processos
Atributo Id not null
Atributo Nome not null
Atributo Status not null
Atributo Data not null
Atributo Acao not null
Atributo Processo_Pai null - Atributo com uma FK apontando para a propria Tabela Processos.
*/
Em nossa Página o atributo processo_pai não é obrigatório, assim possibilita o usuário a deixar nulo o campo, deixando ele alterar o registro em um outro acesso vinculando o processo_pai ao mesmo Id do registro, assim o registro ficará errado.
A forma de tratarmos esse erro é listar todos os processos, menos o processo corrente, travando o usuário de cometer o erro.

O Primeiro passo é:

Criarmos um VO da seguinte forma:
/*
SELECT *
FROM Processos tp
where tp.Processo_id <> :procId
-- procId é a variavel que irá trazer o registro corrente
*/
Declare a variável procId nos "Bind Variables".

Na Página de cadastro no campo Processo_Pai adicione o componente SelectOneChoice baseado no VO que acabamos de criar.

Na PageDef de nossa Página criar uma Action "ExecuteWithParams" amarrando a variável com parâmetro #{bindings.Id} que é o Id do VO base da página.

Dentro da pasta Executables criar um InvokeAction com as seguintes informações:
* Id: // Nome que desejar
* Binds: ExecuteWithParams // Ação que executa o VO com os parâmetros
* Refresh: IfNeeded // Atualização
* RefreshCondition: ${not adfFacesContext.postback} // Condição de execução.

Assim toda a vez que entrar na Página esse InvokeAction será chamado, e a condição do parâmetro será executada.

Deixando sua aplicação mais segura contra erros do usuário.

Até a próxima.