quinta-feira, 10 de setembro de 2009

Criando um Criteria Dinâmico para o objeto LOV - (OAF).

Nesse Exemplo vamos fazer um passo-a-passo de como criar uma Lov dinâmica, recebendo um ou mais parâmentros.

Vamos pensar no seguinte cenário:

Temos um Página onde a mesma tem um FormValue ou qualquer outro campo que tenha uma valor, e esse valor desse campo vai servir como critério para o resultado de uma Lov.

A primeira coisa a ser feita é montarmos o View Object da Lov, não esquecendo de colocar um campo Transient com o mesmo formato do campo que vai servir de Criteria. Lembrando também que esse atributo no VO tem que ser marcado como Passivate.

Depois crie a Região de Lov adicionando uma Table associada ao VO, na mesma crie um FormValue com o atributo Passivate do VO, pois o mesmo vai receber o valor que estava na Página.

Feito isso, crie um Controller na Table da Lov, e adicione o seguinte código no ProcessRequest:

Dictionary passiveCriteria = (Dictionary)pageContext.getLovCriteriaItems();
//Cria um Dictionary, em seguida pega o valor que vem do LovMap da página requisitante
String passiveInvoiceId = (String)passiveCriteria.get("NomeLovMap");

//Instância o Application Module
OAApplicationModule am = (OAApplicationModule)pageContext.getApplicationModule(webBean);
//Chama o método do AM passando o valor que recebemos do LovMap
am.invokeMethod("execQuery", new Serializable []{passiveInvoiceId});

//Executa a Table para trazer todos os registros
if (!pageContext.isFormSubmission()) {
OATableBean table = (OATableBean) webBean;
table.queryData(pageContext);
}

No Application Module criamos um método que executa uma query dinâmica conforme a sua necessidade.

O último passo é na página que chama a Lov, criarmos o LovMap que refere-se ao valor que vamos passar como critério. No mesmo colocamos no "LOV Region Item" o campo que vai receber, no "Criteria Item" passamos o valor da página que vai servir comom critério, e por último marcamos "Programmatic Query" como "True".

Assim conseguimos montar a nossa Lov dinâmicamente conforme a necessidade do negócio.

Abraços e até a próxima.

quarta-feira, 2 de setembro de 2009

[PL/SQL] Esqueça tabelas temporárias: use funções PIPELINED!

Oi Pessoal,

Por várias vezes temos situações de relatórios, por exemplo, em que a consulta ficaria tão complexa que decidimos gerar uma tabela temporária para basear o relatório, ficando o preenchimento das informações a cargo de uma package PL/SQL que é chamada momentos antes do relatório. No entanto, o Oracle 9i em diante nos permite o uso de funções PIPELINED para atingir o mesmo fim, sem ter que criar tabela nenhuma, e sem necessitar controle sobre a transação (commit, usuários concorrentes etc).

Para fazê-lo, os quatro simples passos são:

1) Criar um type no banco do tipo OBJECT que contenha todos os campos necessários na sua query:
create or replace type test_rec as object (key number, value1 varchar2(100), value2 varchar2(200));

2) Criar um outro type, desta vez como uma tabela do type criado anteriormente:
create or replace type tab_rec as table of test_rec;

3) Criar uma função/package a ser chamada do relatório, com o modificador PIPELINED:
 create or replace function get_test(p_key IN NUMBER) return tab_rec pipelined is
begin
for i in 1..p_key LOOP
pipe row( test_rec(i, 'Test'||i, 'This is test number '||i||' for pipelined functions' ));
end loop;
return;
end;


4) Pronto! Agora é só selecionar os registros direto da função, assim:

SELECT *
FROM TABLE(get_test(2));

KEY VALUE1 VALUE2
----------- -------------- ---------------
1 Test1 This is test number 1 for pipelined functions
2 Test2 This is test number 2 for pipelined functions


Abraços pessoal, até a próxima!

terça-feira, 11 de agosto de 2009

[SQL] Como pegar o último valor não-nulo para preencher colunas

Olá pessoal!

Dica rápida interessante de SQL: Imaginem a seguinte situação, que pode acontecer em queries que possuem outer join por exemplo (usarei uma tabela apenas para simplificar o exemplo):

SELECT empregado, gestor FROM empregados

Empregado Gestor
---------- ----------
Joao Luis
Joao NULL
Roberto Joao
Roberto NULL

Essa query trouxe valores duplicados, uma delas com gestor e outra sem. Agora imagine que queremos copiar o valor GESTOR para os valores onde for nulo, agrupando por EMPREGADO. Para isso, podemos usar a função analítica LAST_VALUE, que traz o último valor de uma série, em conjunto com o modificador IGNORE NULLS para ignorar os valores nulos e particionando pela coluna EMPREGADO (que é não-nula):

SELECT empregado, LAST_VALUE(gestor IGNORE NULLS) OVER (ORDER BY empregado) FROM empregados

Empregado Gestor
---------- ----------
Joao Luis
Joao Luis
Roberto Joao
Roberto Joao

Espero que seja útil para livrá-los de enrascadas! Até mais!

sábado, 1 de agosto de 2009

Chamando Metódo com vários parâmetros através de um click em uma Imagem.

Depois de muito tempo sem postar, estamos aqui novamente.

Hoje vamos mostrar como é feito o seguinte cenário:
Imaginem uma tela principal, onde a mesma contém uma Tabela com diversas colunas, e uma das colunas é um campo Imagem, onde eu tenha que chamar algum evento através de um click como a imagem abaixo.




O primeiro passo é colocarmos uma coluna em nossa Table ou AdvancedTable, com um objeto Image. No mesmo adicionar na propriedade Image URL o nome da imagem.
Obs. Segue o link onde contém todas as imagens e seus nomes que existem no servidor o Oracle EBS: http://www.oracle.com/technology/tech/blaf/specs/iconList.html

Em seguida, vamos alterar a propriedade da imagem "Action Type" para fireAction, e altere o atributo Event para um texto mais familiar ao evento. Para passar parâmetros que estão no View Object da nossa tabela, vá na propriedade da imagem "Parameters" e clique no mesmo, abrirá uma form como a imagem abaixo:



Assim podemos passar quantos parâmetros necessitarmo, lembrando que o "Name" é o nome que vamos pegar no Controller, e o "Value" é o ${oa..}.

Para recuperarmos os mesmos dentro do Controller e passarmos para o nosso Appication Module, é bastante simples.

No processFormRequest do controller da página colocamos o seguinte código:



Assim quando clicarmos na imagem ela irá passar os parâmetros do VO, onde pegaremos no Controller e repassaremos para nosso Appication Module, assim podendo fazer as ações que desejarmos como Alterar, Excluir, Processar, Chamar Concurrent e etc...

Um grande abraço e até a próxima.

terça-feira, 2 de junho de 2009

OAF Logging - Escrevendo Log de Erros no OAF

Boa tarde pessoal!

Hoje comentarei sobre o suporte do OAF a uma boa prática de desenvolvimento que é o tratamento correto de erros inesperados. Sabemos que todo sistema Java está sujeito a erros inesperados, sejam eles a falta de permissão para escrever um arquivo em um diretório do sistema operacional, ou então o famigerado NullPointerException, ou até mesmo as SQLExceptions que tratamos na chamada de procedures. No entanto, sabemos também que um erro como o abaixo pode ser extremamente interessante para o DBA ou desenvolvedor, porém não diz nada para o usuário final:

Erro: ORA-04068: Existing State of Packages has been Discarded

Portanto, as boas práticas de desenvolvimento ditam que em um caso desses, devemos silenciosamente gravar este erro em um local que os DBAs ou desenvolvedores monitorem, fazendo com que o mesmo chegue a quem é de interesse, porém mostrar uma mensagem mais amigável ao usuário final, algo como "Ocorreu um erro inesperado, favor contatar o Administrador do Sistema". Este procedimento é chamado de
Logging.

Em uma aplicação java comum, temos o suporte nativo da plataforma para o Logging e também alguns conhecidos frameworks de logging em arquivo ou tela (LOG4J, Commons Logging etc). Agora, trazendo para o nosso mundo Oracle, como podemos prover essa funcionalidade via OA Framework? Poderiamos obviamente utilizar os sistemas acima de logging, porém o OAF nos permite utilizar a ferramenta padrão de monitoramento do aplicativo, chamada Oracle Diagnostics. É um procedimento simples, vamos lá!

Passo 1: Codificar o Logging
O primeiro passo é marcar os pontos de logging no código fonte para que seja exibido pelo Diagnostics. Isto é feito por uma API presente nos objetos OAPageContext, para logging na camada Controller, e OAApplicationModule, para logging no modelo. Por exemplo, para logar uma exceção inesperada no modelo, veja um trecho de código no Application Module:


public void execPack() {
CallableStatement call = new CallableStatement("package",1);
try {
call.execute();
} catch (SQLException sqle) {
if (this.isLoggingEnabled(UNEXPECTED)) {
this.writeDiagnostics(this, sqle.getMessage(), UNEXPECTED);
}
throw new OAException("FND","WF_UNEXPECTED_MESSAGE");

}
}


O código acima faz uma checagem para ver se o nível UNEXPECTED está habilitado no Oracle Diagnostics (veremos como mudar isso nos passos seguintes). Caso afirmativo, irá logar a exceção técnica, logo em seguida disparamos a costumeira OAException, porém com a mensagem padrão WF_UNEXPECTED_MESSAGE que mostrará: "Ocorreu um erro inesperado, favor contatar o Administrador do Sistema". Bem melhor!

Passo 2: Habilitar o perfil FND: Diagnóstico
Quando quiser acompanhar o logging, o administrador do sistema deve trocar o valor do perfil "FND: Diagnóstico" para SIM. Este perfil habilitará, ao lado dos links do topo da tela como Logout, Retornar ao portal etc., um link chamado "Diagnóstico". Ao clicar neste link, aparecerá um dropdown. Escolha a opção "Mostrar Log na Tela", e ele irá perguntar o nível desejado, escolha então "Inesperado (6)". Este nível corresponde ao Logging do tipo UNEXPECTED.



Passo 3: Acessar a página desejada
Ao acessar a página desejada, perceberá que no rodapé da página aparecerá o Logging, no seguinte formato:

[356]:UNEXPECTED:[custom.oracle.apps.xxhr.test.TestAMImpl]:Existing State of Packages has been discarded.


Este tipo de logging em tela é interessante para Teste e Desenvolvimento. Em breve faremos um post explicando como configurar esta mesma funcionalidade, porém gravando em arquivos texto no servidor (para o Logging na base de Produção)
Até a próxima pessoal!