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, 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...

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;




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).
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.



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:



Até a próxima.

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!

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.

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

terça-feira, 1 de julho de 2008

Adicionando controles ao JSF baseado em Switcher

O componente "Switcher" é bastante utilizado para condições de exibições entre componentes JSF como: Controlar CommandLink e OutputText dentro de Tree ou Table. Um cenário bastante comum é a criação de uma Tree, onde seus "nós" podem ser coloridos ou mesmo em forma de Link ou em forma de Texto comum como a Imagem abaixo:


Para conseguir esse tipo de controle, precisamos ter um atributo de controle, onde será feito nosso controle.
Adionar o "Switcher" como o código abaixo:


No xml acima temos a seguinte estrutura:

* Switcher com o facetName = (atributo de controle Mostra) e o valor defaut = "N".

Se o facet for igual a "N" a página irá exibir o componente OutputText com o valor desejado.

Se o facet for igual a "S" a pa´gina irá exibir o componente CommandLink com outro "Switcher".

* Switcher com o facetName = (atributo de controle Associado) e o valor defaut = "S".

Se o facet for igual a "S" o link será exibido na cor "Preto".

Caso contrário o link será exibido na cor "Vermelho".
Baseado no exemplo acima, podemos notar que se aplica a varios cenários de nosso dia-a-dia.

Obs.: O Switcher pode ser utilizado dentro de qualquer componente ADF Faces (Tree, Table, Panel e etc...).

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

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.

quinta-feira, 24 de abril de 2008

Criando Evento Excluir em ADFTable através da Lixeira

Vamos lá pessoal,
Hoje é uma dica bastante interessante, pois é muito utilizada nos aplicativos Oracle (EBS).
Iremos criar uma Página nos padrões web, adicionando uma ADFTable e suas respectivas colunas, onde uma das colunas irá conter o evento "Excluir" que será exibido no formato de "Lixeira".

1º Passo: Adicionar em nossa página uma Table baseada no VO.
2º Passo: Adicionar uma coluna a Table chama "Excluir".
3º Passo: Arrastar a operação "Deletar" para coluna que foi criada em forma de CommandLink.
4º Passo: Criaremos um BackingBean (java Class) que irá conter as seguintes variáveis e métodos:
/*
private OperationBinding actionBindingToExecute;
private OperationBinding commitBinding;
private Object key;//respectivos getters e setters…

public String executeActionBinding() {
actionBindingToExecute.execute();
if (actionBindingToExecute.getErrors().size() == 0) commitBinding.execute();
return "";
}
*/
Dica: para as telas onde tenha as mesma caracterista e funcionalidades, ex.: Consulta com link na table e lixeirinha, aconselhamos a criar um backingBean genérico (ClasseBeanUtils.java).

5º Passo: Criar no CommandLink da Table dois setActionListener com as seguintes propriedades:
* From: #{row.rowKeyStr}
* To: #{ClasseBeanUtils.key} // Chave que criamos no BackingBean

* From: #{bindings.Delete} // Ação de Delete que foi adicionada a página (PageDef).
* To: #{ClasseBeanUtils.actionBindingToExecute} // Chamando método do BackingBean.

6º Passo: O Source da Coluna de nossa Table irá ficar da seguinte forma:

Note que no código acima eu adicionei uma imagem "deleteicon_enabled.gif" que é a Lixeira.
Sua página ficá assim:

7º Passo: Na PageDefinition, crie na seção de "Bindings" duas "Action" baseada no VO da página:
1º: "Commit".
2º: "setCurrentRowWithKey" com os seguintes dados:
· Name ex.: rowKey
· Type ex.: Java.lang.String
· Value ex.: #{ClasseBeanUtils.key}
8º Passo: Precisaremos adicionar nosso BackingBean no "Faces-Config". No faces-config tem a aba "overview" que será criado o "Managed Beans" com o seguintes dados:
· Name ex.: ClasseBeanUtils
· Class ex.: br.com.empresa.view.backing.ClasseBeanUtils
· Scope ex.: request
Após criaremos o "Manager Properties" vinculado ao nosso "Managed Beans" com os seguintes dados:
· Name ex.: commitBinding – ele tem que ter o mesmo nome do backingBean para fazer a injeção de dependência.
· Value ex.: #{bindings.Commit}
Assim nosso exemplo um pouco extenso irá funcionar. Lembrando a todos que esse BackingBean que foi criado podemos utilizar para todas as páginas e eventos parecido, ou seja, o trabalho é feito uma vez na apliação, depois é só o reuso.
Um grande abraço e até a próxima.

quinta-feira, 17 de abril de 2008

Deployment de ADF 10.1.3 para IAS 10.1.2

Olá Pessoal!

Uma situação que costuma causar algum trabalho é quando o cliente utiliza a versão do Oracle AS 10.1.2 (que vem com a versão 10.1.2 do J2EE Container da Oracle, o OC4J) e quer instalar aplicações ADF feitas no JDeveloper 10.1.3.3. Tal situação pede alguma atenção por parte da equipe de desenvolvimento. Seguem portanto alguns problemas que podem ocorrer e a respectiva solução:

Problema: O Servidor 10.1.2 é compatível com a spec J2EE 1.3, e o ADF 10.1.3 por padrão é aderente à J2EE 1.4. Podem ocorrer problemas com o formato dos arquivos de configuração J2EE (web.xml, data-sources.xml, application.xml) que na versão 1.3 usam DTD e na versão 1.4 usam XML Schemas para determinar o formato do XML.
Solução: O wizard de criação destes arquivos no JDeveloper permite que você escolha o formato 1.3 para os mesmos, resolvendo o problema. Ao criar um projeto pelo Wizard, tomem cuidado pois alguns arquivos são auto-gerado, precisamos deletá-los e gerar novamente para termos a opção citada acima.

Problema: O 10.1.2 é compativel com JDK 1.4.2, e o 10.1.3 por padrão é baseado no JDK 1.5. Dará problemas de UnsupportedVersionError ao executar.
Solução: Instale o JDK 1.4.2 na sua estação e configure um novo J2SE Definition dentro do JDeveloper, no menu Tools -> Manage Libraries, aba J2SE Definition. apontando para o arquivo java.exe existente no diretório de instalação do 1.4.2 ele pega o resto. Em seguida, vamos nas propriedades do(s) nosso(s) projeto(s) (botão direito -> Project Properties -> Aba Libraries) e mudamos o J2SE Definition que está lá para 1.4.2. Quando fizermos o rebuild do projeto, já estará compilando na versão antiga.

Problema: O ADF 10.1.3 precisa que estejam instalados no servidor algumas bibliotecas, principalmente pertinentes ao ADF BC e ao Toplink, que estão em uma versão mais antiga no 10.1.2. A aplicação não funcionará.
Solução: Executar o ADF Runtime installer, um programa que automatiza a cópia das bibliotecas do ADF, no servidor 10.1.2. Este instalador está disponível em: http://www.oracle.com/technology/software/products/jdev/htdocs/adfinstaller.html

Problema: Mesmo após executar o ADF Installer, ele está dando erros de NoClassDefFoundError para várias classes...
Solução: O ADF Runtime installer faz apenas parte do trabalho. A Oracle identificou diversos JARs que ficaram faltando, para saber quais devem ser copiados veja os notes no metalink (Notes:358791.1 e 412844.1) que dizem o que deve ser feito no servidor para colocar o ADF 10.1.3 para funcionar no OC4J 10.1.2.

É isso pessoal! Um abraço!

quarta-feira, 9 de abril de 2008

O Componente Shuttle - Parte Final

Olá Pessoal!
Neste post final, ficam só algumas dicas sobre o componente Shuttle:

1) A tag da Shuttle possui um facet chamado filter ([f:facet name="filter"]). Tudo o que for colocado dentro deste facet aparecerá logo acima da lista Heading. Um uso interessante para este facet é quando queremos, por exemplo, colocar um drop-down com uma lista de valores que, quando selecionados, filtram os valores exibidos dentro da Shuttle, como no caso de selecionarmos um departamento no drop-down para que a shuttle contenha apenas os empregados daquele departamento.
Para conseguir isto, se os seus selectItems forem derivados de um View Object, podemos criar um parâmetro de bind nele:
SELECT * FROM Emp EmployeeEO where EmployeeEO.deptno = :dept;
Aí criamos um method binding no Page Definition da página, apontando para o método ExecuteWithParams, e amarramos o parâmetro nomeado "dept" com um af:selectOneChoice, que colocaremos dentro da facet Filter da Shuttle. Feito isso, só precisamos que o componente drop-down submeta a página quando for alterado, o que conseguimos setando o atributo AutoSubmit do componente para verdadeiro.

2) Além da Shuttle comum (af:selectManyShuttle) temos o componente estendido chamado Ordered Shuttle (af:selectOrderShuttle). O funcionamento deste componente é estritamente igual ao da Shuttle comum, com a exceção que na Ordered Shuttle são disponibilizados setas de ordenação do lado direito da Trailing List, de modo que o usuário pode, após selecionar os valores e movê-los para a direita, ordenar estes valores dentro da lista, o que é refletido para a lista resultado montada pela shuttle.

Por hoje é só pessoal! Bom ADF pra vocês!

segunda-feira, 31 de março de 2008

Chamando Páginas como Popups

Boa Tarde Galera,
Hoje o post é referente a chamada de páginas como Popups.

Iremos usar o cenário bem simples com duas páginas, onde a Pagina1.jspx chamará a Pagina2.jspx atravez de um botão ou Link. A ação desse botão ou link é explodir a Pagina1.jspx em formato de Popup conforme imagem abaixo.

A ligação entre as duas páginas é feito atravez do "JSF Navigation Case" que obrigatóriamente terá a propriedade "From OutCome" chamada "dialog:". o "dialog" indica que a página é um popup.

A página1.jspx terá um botão ou Link que irá chamar a outra página atravéz da Action "dialog:". Precisaremos adicionar as seguintes informações nas propriedades:

* UseWindow = true

* Window Height = 300 // tamanho do popup referente a altura da Pagina2.jspx.

* Window Widht = 600 // tamanho do popup referente a largura da Pagina2.jspx.

A Pagina2.jspx irá conter um botão, link ou coisa parecida para retornar a Pagina1.jspx. Nesse componente de retorno será criado um "returnActionListener" com a propriedade "Value" null, assim ao clicar nesse componente o retorno é imediato.

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

quinta-feira, 27 de março de 2008

O componente Shuttle - Parte 2

Oi Pessoal!

Continuando com a série sobre a Shuttle, vamos destrinchar um pouco melhor o funcionamento detalhado do componente JSF que a monta.

O componente af:selectManyShuttle precisa saber quais são os itens que devem ser renderizados nas listas leading e trailing. Isto é feito gerando uma lista de objetos da classe javax.faces.view.SelectItem, ou através de uma tag [f:selectItems] ou através de um loop [f:forEach] que imprima uma sequência de [f:selectItem].
Todo objeto SelectItem tem um valor ("value") e uma descrição. Para informar a shuttle quais valores devem estar do lado trailing (selecionados), montamos uma lista contendo os códigos dos itens selecionados, que devem ser equivalentes ao atributo "value" dos selectItems existentes na Shuttle, e informamos no atributo "value" da própria Shuttle a referÊncia para esta lista no managed bean. Exemplo de shuttle baseada inteiramente no Backing Bean:

[af:selectManyShuttle value="#{ShuttleControl.shuttleValues}"]
[f:selectItems value="#{ShuttleControl.shuttleElements}"]
[/af:selectManyShuttle]

Código do Backing Bean:
public class ShuttleControl {
private int[] shuttleValues; (Lista de códigos, pode ser trocado para List)
private SelectItem[] shuttleElements; (Também pode virar List)

//Getters e Setters omitidos.
}

Exemplo baseado em um ADF Table Binding, usando forEach pra popular os itens (mantendo o backing bean inalterado):

[af:selectManyShuttle value="#{ShuttleControl.shuttleValues}"]
[af:forEach var="li" value="#{bindings.ShuttleElements.rangeSet}"]
[f:selectItem value="#{li.Cod}" description="#{li.Desc}"]
[/af:forEach]
[/af:selectManyShuttle]

PageDefinition desta página:
...
[bindings]
[table iterator="ShuttleVOIter" Id="ShuttleElements"]
[attributes]
[Item name="Cod"/]
[Item name="Desc"/]
[/attributes]
[/table]
[/bindings]


Com esta configuração, podemos colocar um botão na página que a submeta, apontando para um método do Backing Bean da Shuttle. Neste método, a lista com os códigos movidos pelo usuário da leading pra trailing estará disponível no Bean no atributo shuttleValues. Podemos passá-lo para um método do Application Module que faça a inserção programática dos registros no View Object.

Exemplo:
[af:commandButton value="Submeter" action="#{ShuttleControl.onSubmitShuttle}"/]
Método no Backing Bean:
public String onSubmitShuttle() {
OperationBinding method = FacesContext.getCurrentInstance().getValue("#{bindings.applyShuttleValues}");
method.getParamsMap().put("nomeDoparametroList", shuttleValues");
method.execute();
return null; //fica na mesma página
}

Método no Application Module:
public void applyShuttleValues(List nomeDoParametroList) {
ViewObjectImpl view = getShuttleVO();
for (Iterator it = nomeDoParametroList.iterator(); it.hasNext();) {
Integer i = (Integer) it.next();
Row r = view.createRow();
r.setAttribute("Cod", i);
view.insertRow(r);
r.setStatus(Row.STATUS_INITIALIZED);
}
}

No próximo Post vamos demonstrar algumas maneiras de incrementar esta shuttle. Até lá!

quarta-feira, 19 de março de 2008

Dica ADF: Usando o componente Shuttle, Parte 1

Oi Pessoal! Agora que conseguimos colocar a cabeça pra fora da água vou postar aqui. Os últimos dias foram cansativos... mas vamos ao que interessa.

Neste post, vou demonstrar o uso de um dos componentes mais interessantes do ADF Faces, mas pouco usado pela falta de documentação sobre seu uso: o Shuttle, representado pela tag [af:selectmanyshuttle]. Isto é um complemento ao Frank Nimphius em seu blog , onde inclusive existe um projeto de exemplo que pode ser baixado.

O componente Shuttle é composto por duas listas coordenadas entre si, uma delas com os valores possíveis (chamada de leading list) e outra com os valores selecionados (chamada de trailing list). Entre as duas listas, existem controles de mover valor da leading para trailing e vice-versa. Este componente possui também dois facets interessantes, o filter que permite colocar um item acima da lista Leading, como um af:inputText ou af:selectOneChoice, para filtrá-la, e o trailingFooter que permite inserir itens abaixo da lista trailing, como botões de comando etc. O resultado final fica assim:




Vamos entender um pouco mais do seu funcionamento. A Leading List da Shuttle trabalha com um vetor de itens do tipo [af:selectitem], que podem ser populados tanto programaticamente em um Backing Bean, como através de um Table Binding ADF, iremos explorar a segunda opção. Já a Trailing List é baseada em uma lista comum, do tipo java.util.List, contendo o código de cada uma das opções selecionadas baseado na propriedade Code da [af:selectitem]. Segue o código comentado da montagem da Shuttle:

[af:selectmanyshuttle leadingheader="Disponiveis" //-- Cabeçalho da Lista Leading
trailingHeader="Selecionados" //-- Cabeçalho da Lista Trailing
value="#{ShuttleBean.shuttleValues}" //-- java.util.List no Backing Bean
partialTriggers="ShuttleFilter"] //-- Escuta eventos do Filter
[af:foreach var="li" items="#{bindings.Lbc.rangeSet}"]
//--> Dentro do pageDefinition, tenho um Table Binding de nome Lbc. Suas linhas
//--> são representadas pelo rangeSet, para cada uma adicionar um SelectItem
[af:selectitem label="#{li.DescLbc}" value="#{li.CodLbc}"]
[/af:selectitem]
[f:facet name="filter"]
[af:inputtext label="Filtro:" columns="5" valuechangelistener="#ShuttleBean.onFilterHeadingList}" autosubmit="true" id="ShuttleFilter"/]
[f:facet name="trailingFooter"]
[af:panelgroup]
[af:commandbutton text="Aplicar Valores" action="#{LbcShuttleBean.applyShuttleConfig}"]
[/af:commandbutton]
[/af:panelgroup]
[/f:facet]
[/af:selectmanyshuttle]


Este post vai ter mais 3 partes explicando o funcionamento da Shuttle, portanto fiquem ligados, e até mais!

quinta-feira, 13 de março de 2008

Histórico dos atributos.

Normalmente nas aplicações ADF precisamos manter as informações no histórico como:
Quem criou a informação?
Quando foi criada?
Quem fez a última modificação da entidade?
Quando foi modificada?
Quantas vezes a linha foi modificada?
Os Entity Objects armazenam as informações históricas na coluna do atributo conforme imagem abaixo:


Se um atributo de dados é do tipo Number, String ou Date, e não é parte da chave primária, então você pode ativar essa propriedade para ter sua entidade automaticamente manter o atributo de valor históricos para controle interno.

Se você escolher o tipo History Column (Version Number), o ADF automaticamente irá incrementar o valor do atributo numérico a cada vez que o objeto é atualizado. Se você escolher Create on, Create by, Modified on ou Modified by, o valor será atualizado ou criado pelo o usuário ou data corrente.
Até o próximo....
[]'s

terça-feira, 11 de março de 2008

Funcionalidades (Data Integrator e BPEL)

Essa é para a galera que vem entrando no mundo das Integrações. Com a chegada da técnologia Fusion Middleware da Oracle vem crescendo muito a procura por ferramentas de integração para e-Business Suite R12 e legados. Hoje se houve falar muito em ((Bpel - ESB) , BPA e Data Integrator) essas técnologias tem a mesma finalidade mas com caracteristicas diferentes, por exemplo:

* BPA: Ferramenta que vem do mundo ARIS, onde os analistas de negócios criam todas as regras e processos a serem integrados. Após a criação dos fluxos BPAs, é gerado um BPEL que será importado para o JDev para os ajustes técnicos.



* BPEL e ESB: Utilizam um servidor de aplicação e atuam na orquestração dos fluxos de integração, podendo ser desenvolvidas na IDE JDeveloper. São recomendados para pequenos e médios volumes de dados, pois proporcionam mais visibilidade dos processos via BPEL Console e até mesmo utilizando o BAM.

* Data Integrator: Essa Técnologia é voltada para grande volumes de cargas, pois a integração é flexível e muito produtiva, podendo atuar em sistemas de origem e destino heterogêneos. Com o Oracle Data Integrator, o usuário não necessita de um servidor separado para ETL, pois poderá executar as operações de transformação dentro do sistema de origem ou do datawarehouse de destino, melhorando o desempenho, baixando o custo e simplificando a administração.
A solução permite ainda atender a mais de uma centena de bibliotecas de códigos reutilizaveis, que agregam optimizações específicas de origem e destino para bases de dados e pacotes de aplicações.
A utilização da mesma pode trazer beneficios como:
- Integrar grandes quantidades de dados dispersos em ambientes mistos de TI.
- Ótima Performance.
- Escalabilidade.
- Fácil gerenciamento.
- Baixo Custo.

Galera nos próximos posts, detalharemos mais cada uma dessas técnologias.

abraços

ADF: Duas maneiras de popular valores por Sequence

Oi Pessoal! Aqui estamos novamente!

Esta semana tivemos a idéia de demonstrar um dos requisitos mais frequentes dentro dos aplicativos ADF: Popular códigos ou chaves primárias baseados em uma SEQUENCE do banco Oracle.

Neste caso, temos duas situações distintas: quando o próprio aplicativo popula o valor derivado da SEQUENCE, ou quando um programa externo (trigger, PL/SQL) popula o valor no momento da inserção do registro, sem a interferência da aplicação.

Na primeira situação, como o valor da PK é um atributo que deve ser populado logo na criação do registro na tabela (mapeado para um Entity Object), devemos popular no método create(AttributeList) que é o método onde fazemos o defaulting dos valores para entidades novas. Desta maneira:


public void create(AttributeList attr) {

SequenceImpl seq = new SequenceImpl("SEQ_NOME");
this.setAtributoChavePrimaria(seq.getSequenceValue()); //SEQ_NOME.NEXTVAL
}


No segundo caso, como o valor só é populado APÓS o ADF ter passado o controle para o PL/SQL, usamos uma outra funcionalidade dos Entity Objects. Ao abrirmos um Entity Object e selecionarmos o atributo em questão, podemos dizer que seu tipo é DBSequence. Ao fazê-lo, a propriedade "Refresh After Insert" é marcada. Esta propriedade diz para o Entity Object que algum agente externo vai modificar esta entidade após o INSERT na tabela, forçando os View Objects que utilizam esta entidade a reconsultar o estado da mesma logo após o comando de INSERT ser emitido contra o BD. Ou seja, o Entity Object faz o INSERT, a trigger popula a PK, o View Object detecta este "Refresh After Insert" e faz o SELECT novamente.
Abraços, e até!

sexta-feira, 7 de março de 2008

Dica PL/SQL: Criando uma lista IN dinâmica

Boa Tarde pessoal! Vamos a mais uma de PL/SQL que é interessante...

Uma situação que ocorre com frequência em aplicativos ADF é quando precisamos criar uma lista de itens ou checkboxes, em que o usuário seleciona quantos quiser e precisamos montar uma consulta baseada nestes checkboxes. Por exemplo, se o usuário seleciona os checkboxes A, B e C precisamos montar na consulta a cláusula:

AND tabela.campo IN('A','B','C')

Sendo que não sabemos exatamente quantas opções virão marcadas. Uma solução interessante para este caso é o uso do CAST e da função THE no PL/SQL, com o qual fazemos uma cláusula IN aceitar uma TABLE OF VARCHAR2. Aí é só popular esta table com os valores dinâmicos e passar pra consulta!

Primeiro, criamos o tipo:
CREATE TYPE t_empTab
IS TABLE OF VARCHAR2(50); <-- Tem que ser type do banco, não local ou de package

Depois, fazemos uma procedure PL/SQL que pode nos retornar um REF CURSOR por exemplo.

DECLARE
v_empTab t_empTab := t_empTab();
CURSOR c_empTab IS
SELECT empno
FROM scott.emp
WHERE ename IN
(SELECT * FROM THE(SELECT cast(v_empTab AS t_empTab) from dual));
v_empNo c_empTab%ROWTYPE;
BEGIN
v_empTab.EXTEND;
v_empTab(v_empTab.LAST) := 'SMITH';
v_empTab.EXTEND;
v_empTab(v_empTab.LAST) := 'ALLEN';

OPEN c_emp_tab;
RETURN c_emp_tab;
END;

É isso pessoal! Abraços!

quinta-feira, 6 de março de 2008

Bom entendimento: Oracle Forms X ADF BC

Galera, para quem vem do mundo Oracle Forms, segue um comparativo entre Oracle Forms e ADF Business Component. Nessa imagem dá para ter uma visão melhor das familiaridades entre as técnologias.



Qualquer dúvida é só nos enviar.

Abraços

Criando Aplicação ADF - Step-by-Step

Bom Dia Galera,

Para quem está começando a se interessar no mundo Oracle ADF (Application Development Framework), segue o link para criação de uma aplicação step-by-step:
http://www.oracle.com/technology/obe/obe1013jdev/masterdetail_adf_bc/master-detail_pagewith_adf_bc.htm.
(Obs.: Lembrando que no tutorial as imagens irão aparecer quando passarem o "Mouse" nas figurinhas de (Óculos).

Galera, bom divertimento.

quarta-feira, 5 de março de 2008

Pesquisa Linguística: Ignorando Acentos no SQL

Olá pessoal!

Para iniciar as nossas postagens, vamos com uma dica útil aqui nas terras tupiniquins: Como fazer uma pesquisa SQL que ignore acentos na cláusula WHERE.

Para isso, basta trocarmos o método de comparação para linguístico, e tornar a pesquisa binária ignorando acentos:

alter session set nls_comp=linguistic; <-- Pesquisa Linguística
alter session set nls_sort=binary_ai; <-- Binário ignorando acentos

select nome from tabela where nome = 'marcio';

nome
-------------
Márcio
MÁRCIO
marcio

Abraços!
PS: Essa dica foi cortesia do nosso amigo Ricardo Monteiro, grande mestre do PLSQL! Abraços pra ele!

Post Inicial!

Oi Pessoal!
Bem vindos ao mais novo Blog de Tecnologia Oracle do Brasil!

Apresentando os nossos contribuintes:

Thiago Souza - Analista Técnico Oracle Applications e Oracle Fusion Middleware, especialista em Oracle PLSQL com E-Business Suite (AOL), J2EE e Oracle SOA Suite

Robert Nunes - Analista Técnico Oracle Fusion Middleware, especialista em J2EE e Oracle SOA Suite.

Pretendemos postar aqui as nossas descobertas sobre a Tecnologia Oracle que forem interessantes de compartilhar com todos!

Até o próximo post, e abraços!
Thiago / Robert