sexta-feira, 27 de maio de 2011

Como carregar todo tipo de arquivo em Blob?

Boa pergunta hein, e a resposta é mais simples do que voce imagina.

Você só precisa definir um novo atributo na estrutura da transação (em que o Blob esteja definido) para armazenar a extensão do arquivo carregado, e em seguida na propriedade FileTypeAttribute definir esse atributo.

Por exemplo, definimos na estrutura a seguir dois atributos, um para o Blob e outro para a extensão.



Em seguida, basta definir na propriedade FileTypeAttribute  do blob o nome do atributo extensão.

O Genexus tratará as extensões corretas e apresentará o resultado na interface sem nenhum problema, mesmo que estejamos falando de PNG, JPG, XLS, e cuidado! EXE!



Outro cuidado a tomar é o armazenamento do Blob na mesma estrutura principal do registro, a tabela ficará gigante, e consequentemente, lenta.





quarta-feira, 18 de maio de 2011

External Object

Um dos objetos mais interessantes que foi incorporado no Genexus foi o External Object. Se você não o conhece, melhor gastar um pouquinho de tempo pra descobrir a infinidade de recursos possíveis.

Podemos entender esse objeto como sendo um recurso que abre as possibilidades de comunicação entre Genexus e o mundo exterior, ou seja, linguagem de programação, banco de dados, outros sistemas, ..., é um mecanismo importante de conexão Genexus com o entorno do sistema.

Genexus incorporou na ferramenta Tools: Application Integration, que dá uma mãozinha gerando o objeto External Object automaticamente, e são: .Net, Java, WSDL e XML Schema.

Mas é possível com External Object incorporar muitas coisas interessantes no projeto Gx, tais como:

  • Stored Procedures
  • Classes .Net
  • Classes Java
  • Web services
  • EJB´s
  • Schemas de XML
Ou seja, é um recurso muito flexível e interessante.

Maiores informações:

sexta-feira, 13 de maio de 2011

Cache em IFrame

Como forçar a atualização de uma página aberta com um EmbPage? E para piorar, imagine uma carga onde essa página não é HTML mas um arquivo TXT, cujo conteúdo pode ser alterado.

Esse era o meu maior problema do dia, mas felizmente resolvido em 2 minutos, uma página com um IFrame que não poderia ser cacheada no browser, ou seja, deveria ser carregada a cada abertura.
Incluindo o EQUIV-Pragma

Gx não inclui automaticamente o Pragma no inicio do cabeçalho, não no gerador .Net, então é necessário incluí-lo através de um comando MetaEquiv.

<html>
<head>
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="-1">

Para incluir colocar no evento Start a linha de código, a propriedade Expires determina o numero de segundos de validade da página. -1 indica que a página deve ser recarregada instantaneamente, mas é possível nesse local colocar um now() para pegar a data e hora corrente.

Event Start  
    Form.MetaEquiv.AddItem('Pragma', 'no-cache')
    Form.MetaEquiv.AddItem('Expires', '-1')
EndEvent

Esse comando deveria ser suficiente para recarregar a página, mas em algumas situações não funciona, como na minha, :(
Não funcionou
Se você se encontra no time do não funcionou na primeira vez, segue-se outra técnica, via DOM do JS.
Não existem opções no IFrame, e isso não é um problema do Genexus, para determinar o cachê da pagina, inclusive em nosso caso temos a carga não de uma página, mas de um arquivo txt.
A saída foi agregar um parâmetro randômico, junto ao arquivo, de forma a forçar um processamento antes da carga da pagina.  Para isso, uma interrogação seguida de um número randômico (nesse caso a data e hora corrente), resolve. 


 O TextBlock3 deve estar na interface, e marcado com formato HTML.


Agora sim,

No meu caso deu certo, estava utilizando um Internet Explorer modelo 9.0, flex, ..., se você dirige outro modeloprecisa avaliar a questão de compatibilidade do browser aos comandos JS programados.
Agora, o mais estranho de tudo isso, é que ao finalizar a programação JS resolvi comentar todas as alterações e testar novamente a aplicação para ver se o erro de atualização ainda persistia, e imagina o que aconteceu.  Tudo funcionava normalmente, ou seja, alguma coisa foi alterado internamente que corrigiu o problema.  Por via das duvidas mantive os ajustes.

Informações Complementares



segunda-feira, 9 de maio de 2011

TreeView com Controle de Acesso

Após um tempinho no ar da versão de montagem de menus em formato de árvore, chegaram muitos pedidos para agregar uma condição de segurança, isso de forma a filtrar somente os itens possíveis de serem abertos a um determinado grupo de usuários.

Então, para não ficar chato e repetitivo, vamos aplicar o mesmo conceito dos menus recursivos, mas desta vez gerando uma TreeView, que também opera do mesmo modo do JsCookMenu.

ara entender o funcionamento de menus do tipo recursivo, recomendo uma leitura do post anterior (http://profdouglasoliveira.blogspot.com/2010/10/criando-um-menu-recursivo.html) que trata mais profundamente da questão comportamental de menus hierárquicos, os nós, e outros elementos, nesse post estaremos apenas discutindo o TreeView e o parâmetro de segurança.

Tree View


Na versão X o Genexus inovou com a possibilidade de agregar User Controls para aprimorar os resultados da interface web.  Tree View é um dos mais interessantes, e tem por objetivo listar opções de seleção em um formato tipicamente de árvore. Nosso objetivo é produzir um menu que seja filtrado nas operações possíveis de serem realizadas conforme o grupo de usuários. 


 Um WebPanel pode ser programado com os seguintes eventos, sendo que o &PerfilId consiste em um Dynamic Combo Box que permite selecionar o perfil do usuário, e ao ser clicado, se chama a carga do menu.

Event Start
     &selectedTreeNode.Expanded   = 1
EndEvent

Event &PerfilId.Click
     &treeNodeCollectionData      = MenuTreeDP(2, &PerfilId)
EndEvent

O Web Panel, é construído de forma simples, com o Dynamic Combo e o Tree View logo abaixo.


Transações

Nesse exemplo são necessárias duas transações, uma para conter os dados do menu e outra para conter os dados do perfil, conforme apresentamos no diagrama de tabelas abaixo.  MenuTitulo e MenuLink são do tipo Char.


O elemento PaiMenuId é definido como um subtipo de MenuId, ou seja, torna a tabela Menu recursiva.  PaiMenuId deve possuir o Nullable=true na definição desta estrutura.


Para realizar a carga nas tabelas teríamos que definir a de Perfil, com seus diversos grupos de usuários.

E a tabela de Menu com os itens em cada um dos grupos. Essa tabela poderia inclusive ser melhorada para um modelo 1-N, para evitar a repetição dos itens, mas deixemos esse assunto pra lá, a idéia aqui é didática e não otimização.


Data Provider (DP)

Finalmente, para carregar os dados da tabela e apresentar no Tree View necessitamos de um objeto Data Provider. E o mecanismo também é simples, obedecendo a estrutura do TreeNodeCollection SDT, carregando os valores de Id, Name, Link e Target, conforme os valores armazenados na tabela Menu.

TreeNodeCollection
where PaiMenuId = &PaiMenuId
where PerfilId  = &PerfilId when &PerfilId<>0
{
     TreeNode
     {
          Id            = MenuId.ToString()
          Name          = MenuTitulo
          Link          = MenuLink
          LinkTarget    = '_self'
          Nodes         = MenuTreeDP(MenuId, &PerfilId)
     }
}

A linha a seguir, gera a chamada recursiva, ao próprio DP, que no nosso caso se chama MenuTreeDP.
          Nodes         = MenuTreeDP(MenuId, &PerfilId)

Diferente da primeira versão, nessa será necessário fornecer ao DP duas informações, a raiz (&PaiMenuId) e o perfil (&PerfilId) a ser filtrado os itens do respectivo usuário. Portanto,  não se esqueça da regra Parm nesse DP.

parm(
     &PaiMenuId,
     &PerfilId
     );


Conclusão

Esse exemplo é basicamente um complemento do primeiro post, e com poucos ajustes, permite controlar um pouco melhor o menu.

Não se esqueça que o usuário poderá chamar no endereço do Browser os itens que não aparecem no menu, portanto, algo a mais deve ser incorporado nos objetos chamados para evitar acessos indevidos.

E também se faz necessário um pouquinho de WebSession ou Cookie, para gravar o perfil de acesso do usuário, provavelmente definido no login.

Boa programação...