Oi Pessoal,
Como todos sabem, o XML/BI Publisher é a ferramenta padrão para criação de relatórios no EBS R12. No entanto, relatórios com grande volume de dados frequentemente falham quando executados em XML Publisher, com erros como OutOfMemoryError ou erros de lentidão excessiva. Para contornar essa situação, o XML Publisher tem um modo de trabalho chamado escalável (Scalable Mode) que pode ser ativado com configurações simples. O passo a passo:
1. Ligar a opção Scalable Mode para o relatório em questão:
1. System Administrator: Concurrent->Program->Define
2. Consultar o Concurrent do Relatório XML Publisher que desejar ativar
3. Adicionar um parâmetro com o nome ScalableFlag:
? Value Set: yes_no
? Default Value: Yes
? Selecionar checkboxes Enable e Required
? NÃO SELECIONAR checkbox Displayed, para impedir o desligamento em runtime.
? Token precisa ser ScalableFlag (Case Sensitive).
2. Configurar o Administrador do XML Publisher
1. XML Publisher Administrator: Administration -> Configuration
2. General -> Temporary Directory: Setar para o valor da variavel de ambiente $APPLPTMP
3. FO Processing -> Use XML Publisher XSLT PRocessor = True
4. FO Processing -> Enable Scalable Feature of XSLT PRocessor = FALSE
5. FO Processing -> Enable XSLT Runtime Optimizations = True
3. Configurar o Output Post Processor (OPP)
1. Logado como APPS, executar (trocar o -mx2048m pela memoria maxima desejada):
update FND_CP_SERVICES set DEVELOPER_PARAMETERS =
'J:oracle.apps.fnd.cp.gsf.GSMServiceController:-mx2048m'
where SERVICE_ID = (select MANAGER_TYPE from FND_CONCURRENT_QUEUES
where CONCURRENT_QUEUE_NAME = 'FNDCPOPP');
2. Fazer o Bounce do Concurrent Manager
Para melhorar ainda mais a performance, aplicar o patch 7687414 que corrige alguns problemas de ordenação no XDK (XML Developer Kit) usado pelo XMLP para ordenar os registros.
Abraços!!
quarta-feira, 29 de setembro de 2010
quarta-feira, 7 de abril de 2010
Recuperando erro inesperado no Oracle Data Integrator (ODI)
Depois de muito tempo sem postar, estamos aqui novamente, o motivo foi excesso de trabalho (rsrsrsrsrs)
Hoje o Post é de bastante utilidade no desenvolvimento de Integrações, tanto simples quanto complexa.
No desenvolvimento padrão de um ODI, utilizamos vários procedimentos, variáveis e interfaces, porém na execução dos mesmos, poderão ocorrer erros que não estavam previstos e assim fica bastante complicado localizar ou mesmo saber qual foi a origem do erro.
Nesse caso o indicadio criar um procedimento genérico que todos os procedimentos, interfaces ou variáveis apontem o "KO" para ele, assim todo o erro não previsto vai redirecionar para ele com o seguinte código abaixo, você conseguirá exibi-lo:
%=odiRef.getPrevStepLog("MESSAGE")%
Esse comando pode ser utilizado da maneira que você achar mais fácil e que atenda sua necessidade.
Até a próxima...
Hoje o Post é de bastante utilidade no desenvolvimento de Integrações, tanto simples quanto complexa.
No desenvolvimento padrão de um ODI, utilizamos vários procedimentos, variáveis e interfaces, porém na execução dos mesmos, poderão ocorrer erros que não estavam previstos e assim fica bastante complicado localizar ou mesmo saber qual foi a origem do erro.
Nesse caso o indicadio criar um procedimento genérico que todos os procedimentos, interfaces ou variáveis apontem o "KO" para ele, assim todo o erro não previsto vai redirecionar para ele com o seguinte código abaixo, você conseguirá exibi-lo:
%=odiRef.getPrevStepLog("MESSAGE")%
Esse comando pode ser utilizado da maneira que você achar mais fácil e que atenda sua necessidade.
Até a próxima...
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:
2) Criar um outro type, desta vez como uma tabela do type criado anteriormente:
3) Criar uma função/package a ser chamada do relatório, com o modificador PIPELINED:
4) Pronto! Agora é só selecionar os registros direto da função, assim:
Abraços pessoal, até a próxima!
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!
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:

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:
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:
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!
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!
terça-feira, 12 de maio de 2009
OAF - Numeração Automática via Sequence - Sem pular números!
Olá pessoal!
O uso de Sequences para geração de IDs no OAF é, por padrão, feito sobrescrevendo-se o método create() do Entity Object, e dentro dele instanciando um objeto oracle.jbo.SequenceImpl. Um exemplo básico seria:
public void create() {
SequenceImpl seq = new SequenceImpl("MINHA_SEQUENCE");
this.setColunaId(seq.getValue());
}
No entanto, o método create() é executado toda vez que uma linha é criada no VO, ou seja, se o usuário clicar em "Cancelar" e dispensar a linha, a sequence já foi incrementada (o SequenceImpl roda SEQUENCE.NEXTVAL). Portanto, a dúvida é:
Como gerar identificadores via Sequence sem pular números?
A resposta é o método postChanges(), também pertencente ao Entity Object. Este método é chamado somente após todas as validações serem concluídas, alguns momentos antes de inserir a linha no banco. Portanto, é garantia de que qualquer coisa executada neste método só vai rodar se a linha for realmente ser inserida no banco. Por exemplo, escreva isto no seu EntityImpl:
public void postChanges() {
SequenceImpl seq = new SequenceImpl("MINHA_SEQUENCE");
this.setColunaId(seq.getValue());
}
Desta forma, o NEXTVAL na sequence só será chamado quando o framework tiver CERTEZA que a linha vai ser efetivada no BD, eliminando o efeito indesejável de "pulos" no meio da numeração sequencial e que pode ser proibido em alguns casos (ex.: Números de Nota Fiscal).
Até a próxima!
O uso de Sequences para geração de IDs no OAF é, por padrão, feito sobrescrevendo-se o método create() do Entity Object, e dentro dele instanciando um objeto oracle.jbo.SequenceImpl. Um exemplo básico seria:
public void create() {
SequenceImpl seq = new SequenceImpl("MINHA_SEQUENCE");
this.setColunaId(seq.getValue());
}
No entanto, o método create() é executado toda vez que uma linha é criada no VO, ou seja, se o usuário clicar em "Cancelar" e dispensar a linha, a sequence já foi incrementada (o SequenceImpl roda SEQUENCE.NEXTVAL). Portanto, a dúvida é:
Como gerar identificadores via Sequence sem pular números?
A resposta é o método postChanges(), também pertencente ao Entity Object. Este método é chamado somente após todas as validações serem concluídas, alguns momentos antes de inserir a linha no banco. Portanto, é garantia de que qualquer coisa executada neste método só vai rodar se a linha for realmente ser inserida no banco. Por exemplo, escreva isto no seu EntityImpl:
public void postChanges() {
SequenceImpl seq = new SequenceImpl("MINHA_SEQUENCE");
this.setColunaId(seq.getValue());
}
Desta forma, o NEXTVAL na sequence só será chamado quando o framework tiver CERTEZA que a linha vai ser efetivada no BD, eliminando o efeito indesejável de "pulos" no meio da numeração sequencial e que pode ser proibido em alguns casos (ex.: Números de Nota Fiscal).
Até a próxima!
sábado, 11 de abril de 2009
Upload de Arquivos com Self Service E-Business Suite (OAF)
Oi Pessoal!
Seguindo a série de posts sobre OAF, hoje a dica é sobre upload de arquivos via Self-Service do Oracle E-Business Suite.
Em aplicações baseadas em Forms, a Oracle previu a necessidade de anexar documentos a uma determinada entidade, por exemplo anexar a NF digitalizada ao documento fiscal dentro do RI. Para isso, habilita-se um cadastro de Categorias de Anexo e Entidades, para que seja habilitado o botão de anexar (ícone do Clips) dentro do Forms. Ao habilitar este botão, clicando nele o usuário pode fazer o Upload de um arquivo, que é automaticamente anexo ao documento em questão. Isto é feito internamente nas tabelas FND_LOBS (guarda o conteúdo do arquivo em BLOB), FND_DOCUMENTS (dados do documento) e FND_ATTACHED_DOCUMENTS (Associação do DOCUMENT_ID com o PK1_VALUE que representa a chave primária da entidade origem, por exemplo, INVOICE_ID).
Em aplicações OAF, também é possível ativar essa funcionalidade, mesmo sem fazer o cadastro de Entidade mencionado acima. Por exemplo, podemos adicionar um Link de Anexos (Ícone de Clips) em uma coluna de uma Table ou AdvancedTable. Para isto, basta adicionarmos um item do tipo "AttachmentImage" dentro da tabela, conforme abaixo:

Como vocês podem notar acima, o AttachmentImage tem alguns sub-elementos, a saber:
EntityMap (PlayFuncPKMap): é o que define a entidade a qual o anexo será subordinado. no atributo "Entity" devemos inventar um nome que será usado como referência, por exemplo, PlayFuncPK. Todas as telas OAF que tiverem link de anexos para esta mesma entidade (EO) devem usar essa mesma referência.
PrimaryKeys (PlayFuncPK): define qual a chave primária da entidade que deve ser gravada no campo PK1_VALUE da FND_ATTACHED_DOCUMENTS, para guardar a associação anexo/registro. Informe no campo "ViewAttribute" o atributo do VO que é a chave primária do EO correspondente.
CategoryMap (PlayFuncCatMap): define quais categorias de anexo são permitidas para esta entidade. Informe no campo "Category" o nome interno da categoria criada (campo NAME da tabela FND_DOCUMENT_CATEGORIES). Caso não queira limitar as categorias possíveis, é só não incluir o CategoryMap debaixo do EntityMap que ele libera todas.
Após estes simples passos, a tela ficará conforme abaixo, mostrando um ícone de Clips (para visualizar os anexos existentes) e um ícone de Mais ao lado (para adicionar o anexo):

Ao clicar no ícone de Mais, segue-se para a tela de adicionar anexo (core), podendo adicionar anexos do tipo Link, Texto Curto ou então Arquivos (botao browse):

Ao clicar no ícone de Clips, vemos a tabela de anexos:

Abraços, e até a próxima!
Seguindo a série de posts sobre OAF, hoje a dica é sobre upload de arquivos via Self-Service do Oracle E-Business Suite.
Em aplicações baseadas em Forms, a Oracle previu a necessidade de anexar documentos a uma determinada entidade, por exemplo anexar a NF digitalizada ao documento fiscal dentro do RI. Para isso, habilita-se um cadastro de Categorias de Anexo e Entidades, para que seja habilitado o botão de anexar (ícone do Clips) dentro do Forms. Ao habilitar este botão, clicando nele o usuário pode fazer o Upload de um arquivo, que é automaticamente anexo ao documento em questão. Isto é feito internamente nas tabelas FND_LOBS (guarda o conteúdo do arquivo em BLOB), FND_DOCUMENTS (dados do documento) e FND_ATTACHED_DOCUMENTS (Associação do DOCUMENT_ID com o PK1_VALUE que representa a chave primária da entidade origem, por exemplo, INVOICE_ID).
Em aplicações OAF, também é possível ativar essa funcionalidade, mesmo sem fazer o cadastro de Entidade mencionado acima. Por exemplo, podemos adicionar um Link de Anexos (Ícone de Clips) em uma coluna de uma Table ou AdvancedTable. Para isto, basta adicionarmos um item do tipo "AttachmentImage" dentro da tabela, conforme abaixo:

Como vocês podem notar acima, o AttachmentImage tem alguns sub-elementos, a saber:
EntityMap (PlayFuncPKMap): é o que define a entidade a qual o anexo será subordinado. no atributo "Entity" devemos inventar um nome que será usado como referência, por exemplo, PlayFuncPK. Todas as telas OAF que tiverem link de anexos para esta mesma entidade (EO) devem usar essa mesma referência.
PrimaryKeys (PlayFuncPK): define qual a chave primária da entidade que deve ser gravada no campo PK1_VALUE da FND_ATTACHED_DOCUMENTS, para guardar a associação anexo/registro. Informe no campo "ViewAttribute" o atributo do VO que é a chave primária do EO correspondente.
CategoryMap (PlayFuncCatMap): define quais categorias de anexo são permitidas para esta entidade. Informe no campo "Category" o nome interno da categoria criada (campo NAME da tabela FND_DOCUMENT_CATEGORIES). Caso não queira limitar as categorias possíveis, é só não incluir o CategoryMap debaixo do EntityMap que ele libera todas.
Após estes simples passos, a tela ficará conforme abaixo, mostrando um ícone de Clips (para visualizar os anexos existentes) e um ícone de Mais ao lado (para adicionar o anexo):

Ao clicar no ícone de Mais, segue-se para a tela de adicionar anexo (core), podendo adicionar anexos do tipo Link, Texto Curto ou então Arquivos (botao browse):

Ao clicar no ícone de Clips, vemos a tabela de anexos:

Abraços, e até a próxima!
sábado, 4 de abril de 2009
AdvancedTable dentro de AdvancedTable
Bom Dia Pessoal,
Hoje, após um grande período sem posts como o Thiago mesmo falou anteriormente, vamos voltar com alguns assuntos bastante interessante referente a OAF (Oracle Applications Framework).
Para quem não conhece, OAF é a tecnologia que a Oracle utiliza para Customização e Desenvolvimento de Páginas WEB dentro do ERP (eBS).
E como é uma recomendação da própria Oracle a não utilização do Forms nas próximas releases, vamos iniciar uma sessão de posts interessantes para quem quer iniciar ou mesmo os desenvolvedores mais experientes. O Post de hoje é muito interesasnte, pois se trata de uma Página contendo uma AdvancedTable dentro de outra AdvancedTable.
Nosso objetivo é criar uma página onde a visualização fique bastante facilitada, por conta do Máster-Detail entre as tabelas, como a imagem abaixo.

Hoje, após um grande período sem posts como o Thiago mesmo falou anteriormente, vamos voltar com alguns assuntos bastante interessante referente a OAF (Oracle Applications Framework).
Para quem não conhece, OAF é a tecnologia que a Oracle utiliza para Customização e Desenvolvimento de Páginas WEB dentro do ERP (eBS).
E como é uma recomendação da própria Oracle a não utilização do Forms nas próximas releases, vamos iniciar uma sessão de posts interessantes para quem quer iniciar ou mesmo os desenvolvedores mais experientes. O Post de hoje é muito interesasnte, pois se trata de uma Página contendo uma AdvancedTable dentro de outra AdvancedTable.
Nosso objetivo é criar uma página onde a visualização fique bastante facilitada, por conta do Máster-Detail entre as tabelas, como a imagem abaixo.
Primeiro Passo: Nesse caso teremos dois ViewObjects (VO) ligados através de um ViewLink (VL). Imaginem uma tabela de Períodos e outra de Trabalhos realizados, onde a ligação entre as mesmas seja o atributo PeriodId, existe vários trabalhos realizados para cada período. Seu ApplicationModule (AM) vai ficar dessa forma:
Crie uma página comum Oracle Applications (OA), na mesma você pode criar uma região para que a tabela fique mais organizada. Adicione uma AdvancedTable dentro da Região criada, e atribua suas respectivas colunas referente ao VO de Períodos conforme sua necessidade, feito isso vamos clicar com o botão direto na mesma e habite a opção “detail”.
Dentro do “detail” vamos adicionar outra AdvancedTable que será baseada no VO de trabalhos Realizados. A imagem abaixo irá ilustrar a estrutura da página.

Terceiro Passo: Criar o Controller (CO) da página, onde será criado a amarração entre os VO´s através do VL.
No método do controller “processRequest”, vamos colocar o seguinte código:
OAWebBean outerTable = (OAWebBean)webBean.findChildRecursive("AdvancedTableRN");
OAWebBean innerTable = (OAWebBean)webBean.findChildRecursive("SubAdvancedTableRN");
if (outerTable != null)
{
//temos que setar exatamento o atributo do VO
outerTable.setAttributeValue(CHILD_VIEW_ATTRIBUTE_NAME,"PeriodId");
// temos que setar exatamento o valor do VL que está no AM
outerTable.setAttributeValue(VIEW_LINK_NAME,"PeriodToWorkRealizedVL");
}
if (innerTable != null)
{
//temos que setar exatamento o atributo do VO
innerTable.setAttributeValue(CHILD_VIEW_ATTRIBUTE_NAME,"PeriodId");
// temos que setar exatamento o valor do VL que está no AM
innerTable.setAttributeValue(VIEW_LINK_NAME," PeriodToWorkRealizedVL ");
}
Feito esses 3 passos acima, é só rodar a página e visualizar o resultado.
Esse foi mais um post da série OAF, um grande abraço e boa diversão.
Terceiro Passo: Criar o Controller (CO) da página, onde será criado a amarração entre os VO´s através do VL.
No método do controller “processRequest”, vamos colocar o seguinte código:
OAWebBean outerTable = (OAWebBean)webBean.findChildRecursive("AdvancedTableRN");
OAWebBean innerTable = (OAWebBean)webBean.findChildRecursive("SubAdvancedTableRN");
if (outerTable != null)
{
//temos que setar exatamento o atributo do VO
outerTable.setAttributeValue(CHILD_VIEW_ATTRIBUTE_NAME,"PeriodId");
// temos que setar exatamento o valor do VL que está no AM
outerTable.setAttributeValue(VIEW_LINK_NAME,"PeriodToWorkRealizedVL");
}
if (innerTable != null)
{
//temos que setar exatamento o atributo do VO
innerTable.setAttributeValue(CHILD_VIEW_ATTRIBUTE_NAME,"PeriodId");
// temos que setar exatamento o valor do VL que está no AM
innerTable.setAttributeValue(VIEW_LINK_NAME," PeriodToWorkRealizedVL ");
}
Feito esses 3 passos acima, é só rodar a página e visualizar o resultado.
Esse foi mais um post da série OAF, um grande abraço e boa diversão.
quinta-feira, 2 de abril de 2009
Submeter Concurrent via Self-Service (Após um longo inverno...)
Oi Pessoal!
Sei que faz algum tempo que não postamos aqui no blog, mas tudo tem seu lado bom: coletamos bastante "material" para enriquecê-lo e compartilhar o conhecimento com a comunidade da Tecnologia Oracle.
Para reiniciar com o pé direito, fica uma dica simples e rápida: Sabemos que através de qualquer responsabilidade, podemos acessar a fila de concorrentes e submeter um novo pelo menu "Exibir -> Solicitações". No entanto, o que é importante notar é que existe uma função core que permite que façamos exatamente o mesmo através do Self-Service Web Oracle Applications, sem sequer entrar no Forms.
Para conseguir que o usuário submeta um concurrent pela Web, basta adicionar ao menu da responsabilidade uma função chamada "Submeter Solicitações" (Código FNDCPSRSSSWA) ou então, se o objetivo é somente exibir a fila dos concorrentes submetidos, adicionar a função "Exibir Solicitações" (Código FNDCPVIEWREQUEST). Experimentem!
Até a próxima!
Sei que faz algum tempo que não postamos aqui no blog, mas tudo tem seu lado bom: coletamos bastante "material" para enriquecê-lo e compartilhar o conhecimento com a comunidade da Tecnologia Oracle.
Para reiniciar com o pé direito, fica uma dica simples e rápida: Sabemos que através de qualquer responsabilidade, podemos acessar a fila de concorrentes e submeter um novo pelo menu "Exibir -> Solicitações". No entanto, o que é importante notar é que existe uma função core que permite que façamos exatamente o mesmo através do Self-Service Web Oracle Applications, sem sequer entrar no Forms.
Para conseguir que o usuário submeta um concurrent pela Web, basta adicionar ao menu da responsabilidade uma função chamada "Submeter Solicitações" (Código FNDCPSRSSSWA) ou então, se o objetivo é somente exibir a fila dos concorrentes submetidos, adicionar a função "Exibir Solicitações" (Código FNDCPVIEWREQUEST). Experimentem!
Até a próxima!
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:
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:
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!
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:
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:
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:
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:
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!
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
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, 24 de outubro de 2008
JDeveloper 11g Production
É galera agora é verdade...
No OpenWorld 2008 foi lançado o JDev 11g Production, podemos desenvolver todas as nossas aplicações ADF/BPEL/ESB/SQL e etc... utilizando o servidor de aplicação WebLogic - BEA.
Para baixar o Jdev11g é só acessar a url: http://www.oracle.com/technology/products/jdev/index.html
O pessoal da Oracle adicionou algumas demonstrações de novas funcionalidades, segue link: http://www.oracle.com/technology/products/jdev/viewlets/viewlet.html
Eles também disponibilizaram uma biblioteca de documentações para os desenvolvedores Oracle Fusion Middleware Release (11.1.1), a documentação está no formato (HTML e PDF).
http://download.oracle.com/docs/cd/E12839_01/index.htm
Segue também alguns tutoriais passo-a passo: http://www.oracle.com/technology/obe/obe11jdev/11/index.html
Para tirar dúvidas tem o bom e velho fórum, onde podemos discutir e tirar dúvidas: http://forums.oracle.com/forums/forum.jspa?forumID=83
Com esses links, já temos brincadeira para bastante tempo...
Abraços e até a próxima...
No OpenWorld 2008 foi lançado o JDev 11g Production, podemos desenvolver todas as nossas aplicações ADF/BPEL/ESB/SQL e etc... utilizando o servidor de aplicação WebLogic - BEA.
Para baixar o Jdev11g é só acessar a url: http://www.oracle.com/technology/products/jdev/index.html
O pessoal da Oracle adicionou algumas demonstrações de novas funcionalidades, segue link: http://www.oracle.com/technology/products/jdev/viewlets/viewlet.html
Eles também disponibilizaram uma biblioteca de documentações para os desenvolvedores Oracle Fusion Middleware Release (11.1.1), a documentação está no formato (HTML e PDF).
http://download.oracle.com/docs/cd/E12839_01/index.htm
Segue também alguns tutoriais passo-a passo: http://www.oracle.com/technology/obe/obe11jdev/11/index.html
Para tirar dúvidas tem o bom e velho fórum, onde podemos discutir e tirar dúvidas: http://forums.oracle.com/forums/forum.jspa?forumID=83
Com esses links, já temos brincadeira para bastante tempo...
Abraços e até a próxima...
quinta-feira, 23 de outubro de 2008
Dicas: Como usar o PARTITION BY
Essa é uma dica muito interessante.
Imaginemos a seguinte query:
1. Select deptno, ename, job, sal
2. from EMP
3. order by deptno, ename;
O resultado seria:

Agora precisamos encontrar o menor salário e o maior salário de cada departamento, mas listando todos os empregados. Para isso podermos fazer assim:
1. Select deptno, ename, job, sal,
2. Min(sal) over (partition by deptno) as MENOR,
3. Max(sal) over (partition by deptno) as MAIOR
4. From EMP
5. Order by deptno, ename;

Imaginemos a seguinte query:
1. Select deptno, ename, job, sal
2. from EMP
3. order by deptno, ename;
O resultado seria:
Agora precisamos encontrar o menor salário e o maior salário de cada departamento, mas listando todos os empregados. Para isso podermos fazer assim:
1. Select deptno, ename, job, sal,
2. Min(sal) over (partition by deptno) as MENOR,
3. Max(sal) over (partition by deptno) as MAIOR
4. From EMP
5. Order by deptno, ename;
Separei em cores para visualizarmos melhor. A função min e max que normalmente utilizamos com group by foi utilizada com a opção OVER, caracterizando-a como uma função analítica.
No nosso exemplo, as funções MIN e MAX estão sendo executadas apenas sobre os registros de cada departamento. Consigo isso criando uma partição lógica (window) através do OVER (PARTITION BY deptno).
No nosso exemplo, as funções MIN e MAX estão sendo executadas apenas sobre os registros de cada departamento. Consigo isso criando uma partição lógica (window) através do OVER (PARTITION BY deptno).
Abraços e até a próxima
quarta-feira, 1 de outubro de 2008
Ordenando Registros em Query Hierarquica - SIBLINGS
Galera essa dica veio do nosso grande Mestre Ricardo Monteiro.
Nosso exemplo abaixo, demonstra como ordenar uma query hierarquica com conect by utilizando o SIBLINGS:
Temos a tabela de Empregados:

Vamos então mostrar a hierarquia dos empregados, ou seja, os chefes e seus subordinados.
Nosso exemplo abaixo, demonstra como ordenar uma query hierarquica com conect by utilizando o SIBLINGS:
Temos a tabela de Empregados:
Vamos então mostrar a hierarquia dos empregados, ou seja, os chefes e seus subordinados.
Notem que os empregados não estão em ordem alfabética.
Notem que a hierárquia está comprometida.
O que precisamos é que o order by “aja” apenas dentro da cada nível da hierarquia. Para isso usamos a cláusula SIBLINGS no order by:
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!
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!
sexta-feira, 15 de agosto de 2008
Criando Templates com Oracle Bpel
A nossa dica de hoje, é referente ao Oracle Bpel.
É muito comum criarmos templates para criação de diversas aplicações, no Oracle Bpel não é diferente.
Como o desenvolvimento do Oracle Bpel pode ser um pouco complexo, principalmente na criação de (Logs, emails e validações), temos a opção de criação de diversos templates, veja como:
Abra o Jdeveloper e crie uma nova aplicação Bpel, adicionando os componentes que deverão servir como Template.

Após a definição dos padrões, salve a aplicação e clique com o botão direito no Objeto. Abrirá a opção de "Mark as Template".

Feito isso, o template foi criado com sucesso.
Para testar crie um novo projeto "Bpel" que irá aparecer o template criado acima, conforme imagem.

Selecione o template "OracleTechTips Templates" e o novo projeto estará com os componentes definidos acima.
(Obs.: É possível criar o número de templates necessários).
Abraços e até a próxima.
É muito comum criarmos templates para criação de diversas aplicações, no Oracle Bpel não é diferente.
Como o desenvolvimento do Oracle Bpel pode ser um pouco complexo, principalmente na criação de (Logs, emails e validações), temos a opção de criação de diversos templates, veja como:
Abra o Jdeveloper e crie uma nova aplicação Bpel, adicionando os componentes que deverão servir como Template.
Após a definição dos padrões, salve a aplicação e clique com o botão direito no Objeto
Feito isso, o template foi criado com sucesso.
Para testar crie um novo projeto "Bpel" que irá aparecer o template criado acima, conforme imagem.
Selecione o template "OracleTechTips Templates" e o novo projeto estará com os componentes definidos acima.
(Obs.: É possível criar o número de templates necessários).
Abraços e até a próxima.
sexta-feira, 18 de julho de 2008
Como Construir um SelectOneChoice Hierarquico no ADF Faces RC.
Galera essa dica é para aqueles que iniciaram suas pesquisas com o Jdeveloper 11g.
Nosso case, foi desenvolvido por Frank Nimphius.
O exemplo abaixo, iremos construir um DropDown com o componente SelectOneChoice, onde o mesmo irá listar os "Departamentos" e seus "Empregados" em forma de hierarquia, como a imagem abaixo.

Para a implementação do lista, é preciso criar um View Object (VO) hirarquico, baseado no "departamento" e "empregado". O VO pode ser arrastado ou criado manualmente para a tela, em forma de SelectOneChoice. O código deve ficar da seguinte forma:
<af:selectOneChoice id="selectBox" label="Choose Employee" valuePassThru="true"
styleClass="employeeSelectBox"unselectedLabel="Choose Employee">
<af:forEach items="#{bindings.DepartmentsView1.children}" var="departments">
<af:selectItem label="#{departments.DepartmentName}" disabled="true"/>
<af:forEach items="#{departments.children}" var="employees">
<af:selectItem label="#{employees.LastName}" value="employees.EmployeeId"/>
</af:forEach>
</af:forEach>
Note que o primeiro "forEach" é baseado no VO de departamentos e exibe o atributo DepartamentName. O segundo "forEach" é baseado no Filho do VO de departamentos como
#{departaments.children}.
Para aplicar a cor a lista, é utilizado o css, onde o selectOneChoice tem sua propriedade styleClass.
Para quem quiser fazer o download do projeto, acesse:
http://www.oracle.com/technology/products/jdev/tips/fnimphius/selectonechoicegroups/HierarchicalSelectOneChoice.zip
Até a próxima.
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
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
Assinar:
Postagens (Atom)