quinta-feira, 22 de março de 2012

Voando baixo...

Já ouviu falar daquela estória de que quando você está num poço cheio de coisas que exalam um cheiro fortemente desagradável, melhor é enfiar a cabeça para não sentir o cheiro? Lembrando que esse é um blog de respeito, e não posso utilizar palavras impróprias. Então, acho que funciona assim também no momento em que ocorre algo inesperado, sem explicação, e no final das contas não se tem muito mais o que fazer a não ser isso mesmo, pular de cabeça!

Com a opção de instalação dos upgrades, ocorre um efeito mais ou menos semelhante, pois esperamos, esperamos, e de repente a espera foi tanto que não restam muitas alternativas, e no fim das contas, vira um poço bem cheio, e dai não tem solução, ou você atualiza ou já era.  Backup também segue o mesmo principio, não queremos perder nosso tempo fazendo backups, e assim vamos postergando, ..., até que um dia, perdemos até semanas para recuperar-se do estrago.

Mistério!

Esse é o causo de hoje, de repente todas as minhas kbs perderam literalmente contato com o GxServer. Sem aviso, sem nenhuma desculpa, simplesmente uma nova mensagem surgiu:


Nada de novo havia acontecido, apenas uma instalação do Beta do GxPlorer 7.0, para inocentes fins de teste.

Situação difícil, porque não havia razão para este problema. Esse equipamento estava muito bem estabilizado, sem problema algum, sem nenhum defeito, e a um ano sem receber maiores atenções na instalação do Gx, upgrade #U5, já tendo a #U7 disponível para instalação.  Então como explicar que algo tão estabilizado poderia ser afetado de forma tão drásticas.
  1. A instalação do GxPlorer afetou o Genexus?
  2. A falta de atualização do Genexus não combinou com o GxPlorer?
  3. Outra situação desconhecida afetou o sistema?
Reinstalação ou Atualização do Genexus

A desconfiança recaiu sobre a atualização faltante. O mundo perfeito seria atualize imediatamente quando um novo upgrade é disponibilizado, mas a experiência passada nos faz olhar tudo com muita desconfiança, pois uma política de manter tudo atualizado também tem suas consequências, pois de vez em quando atualizamos o Genexus e novos bugs surgem, perdemos a estabilidade por um certo tempo, ficamos cheio de receios que algo vai dar errado.  Por outro lado, sem atualizações de repente o mundo acaba.

Removemos a instalação do GxPlorer, só pra garantir, e sem outra opção no momento, atualizamos o Gx para o #U7, e advinha, tudo voltou ao normal. Para tirar da cisma, reinstalamos o GxPlorer e o problema novamente voltou, então, o que podemos concluir?
  1. Manter o Genexus atualizado é uma boa prática, mas antes de optar pelo seu uso ou não é melhor testar em outro equipamento/kb
  2. Uma opção para coisas inexplicáveis é a reinstalação do próprio Genexus, prática interessante que não causa outros efeitos colaterais, e resolve uma série de situações.
  3. Antes de instalar qualquer coisa na máquina de desenvolvimento, melhor testá-la em outro equipamento, mas isso também não garante que tudo dará certo, os equipamentos costumam ser diferentes.
  4. Reinstalar o Genexus não causa perda da licença, pois as mesmas são controladas pelo Licence Manager e não o Gx.
  5. Cuidado ao misturar as versões de produtos de teste no equipamento de desenvolvimento, as versões beta tem a finalidade exata de ser apenas beta, ou seja, mostrar as falhas que precisam ser corrigidas, e essa era uma delas.
Veja que mesmo com a relutância em atualizar o sistema, de fato esse não era o problema e sim compatibilidade com outro produto.  Portanto, caso passe por algo semelhante você tem duas opções, reinstalar o Genexus ou atualizá-lo caso haja essa possibilidade. Sejamos tradicionais, primeiro a reinstalação. Ou ainda um banho de lama, dizem que até faz bem!

quarta-feira, 21 de março de 2012

SmartChallenge Brasil 2012

Excelente noticia para os Universitários. A Artech está promovendo o SmartChallenge Brasil nos mesmos moldes do concurso que ocorreu no último Encontro Genexus de Montevideo. Excelente oportunidade para aprender e utilizar o Genexus X Evolution 2.



terça-feira, 20 de março de 2012

Jakarta POI 32 Bits em IIS de 64 Bits

Essa discussão já é antiga, mas infelizmente sem solução ainda, pelo menos gratuita. Surgiram muitas boas idéias, mas infelizmente todas requerem muito tempo, esforço e dedicação para que o resultado final seja de fato satisfatório, então, como não dispomos pelo menos do primeiro fator, vamos a uma solução 'paliativa', para não dizer 'gambiarrativa'.

Aliás, só um comentário, mesmo com toda a evolução dos sistemas, o Excel ainda é uma ferramenta indispensável no nivel gerencial, não? Interessante isso, ainda não surgiu um mecanismo tão eficiente para visualizar, manipular, avaliar, filtrar, informações.

A questão da geração de Excel em Genexus, já é um assunto meio delicado, que necessita de bibliotecas externas acopladas ao sistema, assunto já bastante discutido e explorado anteriormente em dois Posts:
Portanto, temos o  o Jakarta.POI e o ExcelLite, e ambos operam de modo muito semelhante, mas trazem consigo restrições:
  1. JakartaPoi: sem restrições operacionais, gratuito e roda apenas em 32 bits, e se seu sistema for 64 você será premiado com a seguinte mensagem:
    Não foi possível carregar arquivo ou assembly 'file:///C:\Models\Teste\Teste1\CSharpModel\web\bin\Jakarta.POI.dll' ou uma de suas dependências. Foi feita uma tentativa de se carregar um programa com um formato incorreto.
    como fazer entao:
  2. ExcelLite: roda em 32 ou 64 bits, possui uma versão gratuita mas com o limite de 150 linhas por planilha.
Então, se o Jakarta resolve a situação, temos a opção de permitir que rode no IIS7.0, em nosso belo Windows 64Bits. Solução viável, mas entenda, não definitiva.



Operação 64To32Bits
Seria quase um DTOC() ou CTOD(), mas nesse caso com consequencias ruins no final das contas, pois a idéia aqui é baixar o nível de 64 para 32 bits, ou se preferir, 'compatibilizar' o IIS para rodar DLL's de 32 no servidor de 64 bits.
  1. Execute o comando para ver quais Pools estão configurados em seu IIS 7.0 para rodar com 32 bits.

    C:\Windows\System32\inetsrv\appcmd.exe list apppool /Enable32BitAppOnWin64:true
     
  2. Se sua aplicação não aparecer na lista resultante, então será necessário inclui-la no modo de compatibilização.

    C:\Windows\System32\inetsrv\appcmd set config -section:applicationPools -applicationPoolDefaults.enable32BitAppOnWin64:true
Feito isso, sua aplicação estará apta a rodar o Jakarta POI normalmente no IIS 7.0, mas vou deixar as conclusões dessa iniciativa para você mesmo avaliar.

Outra possibilidade é no próprio IIS habilitar a propriedade do POOL (Habilitar Aplicativos de 32-Bits), em Configurações Avançadas http://www.genexando.com/2011/07/attempt-was-made-to-load-program-with.html)

Caso queira saber o comportamento do IIS com isso, pode encontrar maiores informações em  http://learn.iis.net/page.aspx/201/32-bit-mode-worker-processes/

Genexus X Evolution 2

Finalmente lançado no México o Genexus X Evolution 2.

Uma palavra: espetacular!

http://www.genexus.com/evolution2

terça-feira, 13 de março de 2012

Grids Dinamicos

Genexus atende muito bem aos casos em que as informações estão comportadas em tabelas previamente definidas, planejadas inicialmente por meio de transações, estruturas, atributos, ou seja no momento do design do software, mas o que dizer em situações que temos o conjunto a ser definido de dados somente em runtime? em outras palavras, quem define esse conjunto, por exemplo, seria o usuário por meio de uma interface.

Esse tema remete a vários problemas de programação, uma lista extensa que não cabe aqui explorar, mas o que mais me interessa nesse instante é a apresentação dessa estrutura nova, em uma situação em que não sabemos de antemão quais atributos deverão ser apresentados ao usuário.

Portanto, separemos o tema em dois, o armazenamento e em seguida a apresentação, e exploremos somente este último, por enquanto.

Grid Dinâmico

O controle Grid é um dos componentes mais utilizados e importantes na interface Genexus, e isso é facil de explicar porque, pois o mesmo é um mecanismo que se encarrega de selecionar, filtrar, apresentar, pesquisar informações armazenadas em uma tabela dita estendida, ou seja, a partir de uma determinada tabela base, todas as relacionadas N-1 a essa, em modo cascata, ou seja, atingindo aos niveis mais baixos e distantes do diagrama com um unico controle. Quer mais?

Infelizmente, tem um 'defeito', opera sob o modelo conceitual Genexus e claro, somente com as regras definidas pelo Genexus, atributos, tabelas pertencentes a esse modelo conceitual, em outras palavras, para 99,9% dos casos atende sem maiores dificuldades pois Genexus opera de forma muito eficaz em modo comportado.

Não sei a respeito dos seus problemas de programação, mas de vez em quando enrosco nesse 0,1% da estatística, com situações onde o modelo comportado não atende, ou mesmo, por pura frescura, desejo apresentar uma interface diferente para o usuário.  Vamos assumir essa segunda possibilidade, ok.

Como fazer então? para um grid tradicional é necessário um atributo previamente criado em alguma estrutura de transação, é necessário colocar esses atributos nas colunas do grid, e isso somente pode ser realizado em modo design?  A resposta: gxuiGrid.

gxuiGrid x gxuiGridExtension

Genexus implementa o grid do tipo gxui em duas formas distintas, o gxuiGrid tradicional, e o gxuiGridExtension, este ultimo trata de converter um grid tradicional Genexus no padrão visual do gxui, o resultado é ótimo em ambos os casos.

Existe no entanto uma diferença significativa entre os componentes: colunas dinâmicas e mecanismos tradicionais de carga e recuperação.

gxuiGrid
gxuiGridExtension
colunas dinâmicas
sim
nao
conteúdo dinâmico
sim
sim
evento Refresh
não
sim
evento Load
não
sim
for each line
não
sim

Para você entender direito, vou simplificar, com o gxuiGrid você tem mais flexibilidade para montar o que deseja mas não tem para recuperar a informação do Grid. Com o gxuiGridExtension você tem um modelo tradicional de carga, design, ..., mas com a aparência do gxuiGrid, mas sem tanta flexibilidade assim.  Portanto, existe espaço para dois sobreviverem, e para o gxuiGrid, uma necessidade de melhoria para que se permita por exemplo utilizar um for each line no mesmo.  Se seu problema se resume a apresentar a informação, então você está tranquilo, a questão é a recuperação dos dados para exportá-los para o Excel, por exemplo.

Vamos ao Exemplo

Seguindo a linha do Genexando vamos a um exemplo simples para não complicar muito a vida.  De quebra, vamos carregar um gxuiGrid com um conjunto variável de dados.  No exemplo, temos uma tabela, Estrutura, e na mesma diversos atributos (Titulo, CampoNome, Width, Hidden), que armazenam a composição desejada no gxuiGrid.  Essa tabela é responsável por manter a estrutura do Grid.
 for each
  if &tam > 0
    &gxuicoluna = new()
  endif
  &gxuicoluna.header = EstruturaTitulo.Trim()
  &gxuicoluna.dataIndex = EstruturaCampoNome.Trim()
  &gxuicoluna.width = EstruturaWidth
  &gxuicoluna.css = 'font-size:12px; color:#000000;'
  &gxuicoluna.dataType = gxuiDataType.string
  if EstruturaHidden =1
     &gxuicoluna.hidden = gxuiBoolean.True
  else
     &gxuicoluna.hidden = gxuiBoolean.False
  endif
  &gxuiGridColumnModel.Columns.Add(&gxuicoluna)
  &tam = 1
endfor

Para que funcione direitinho, carregue a tabela Estrutura com a definição dos campos que deseja colocar no Grid. No exemplo, utilizei no campo EstruturaCampoNome nomes simples como Coluna01, Coluna02, ... e por ai vai. A variável &gxuicoluna do tipo gxuiGridColumn, é utilizada para carregar a coleção de colunas em &gxuiGridColumnModel.  Veja que para simplificar poderiamos utilizar aqui um DataProvider, mas propositalmente coloquei em um for...each, para exercitar um pouco a respeito de coleções.


Uma vez construido o Grid, agora o foco é carregá-lo com alguma coisa. O segredo é ter uma coleção em que os nomes dos itens coincidam com os nomes das colunas definidas para o gxuiGrid, como por exemplo o SDT abaixo.
 
E a carga pode ser algo simples como a apresentada a seguir.
for &it = 1 to 10
  &gxuiGridDataItem.Coluna01 = str(&it * 1)
  &gxuiGridDataItem.Coluna02 = str(&it * 2)
 
&gxuiGridDataItem.Coluna03 = str(&it * 3)
  &gxuiGridDataItem.Coluna04 = str(&it * 4)
  &gxuiGridDataItem.Coluna05 = str(&it * 5)
  &gxuiGridData.Itens.Add(&gxuiGridDataItem)
  &gxuiGridDataItem = new()
endfor

A variável &gxuiGridData deve ser do mesmo tipo do SDT gxuiGridData, e a variável gxuiGridDataItem do tipo gxuiGridData.Item.


Antes de finalizar mais uma dica, na propriedade do gxuiGrid, não se esqueça de definir a variável que contém a carga &gxuiGridData, e o elemento inicial da coleção, que no nosso SDT se chama Itens.


Conclusão

Para quem está acostumado com a normalidade do Grid tradicional do Genexus, o gxuiGrid assusta um pouco, mas veja que vale a pena estudá-lo, dá pra pensar quantas excelentes oportunidades ele abre? de fato o controle é legal mesmo, portanto só nos resta agradecer ao pessoal da Artech pelo esforço para disponibilizá-lo para nós.

Quer aprender mais? instale a kb do RSSReader, disponivel no gxserver, e veja também como funciona o gxuiGridExtension


sexta-feira, 2 de março de 2012

Link Target

Links aparentemente são métodos de chamada que poderiam ser completamente ignorados se não fosse por uma característica muito interessante: permitir abrir um objeto em uma nova janela.  Muitos poderiam argumentar que abrir novas janelas no navegador não é coisa muito inteligente, mas certos objetos se dão melhor em janelas novas, como é o caso de planilhas e relatórios PDF.   Portanto, esse post tem por objetivo explorar um pouco a respeito da programação do Link e também compará-lo com os demais recursos que também abrem janelas no Genexus.


Link.Target e Events
Esse é o diferencial, pois é possível definir o target do link, o alvo, que podem ser os tradicionais: blank, self, parent, , e por ai vai.

Mas para que o mesmo funcione, a primeira coisa a ser considerada é que essa propriedade deve ter sido previamente programada e disponibilizada na interface do usuário.   Portanto, o LinkTarget já deve ter sido definido quando o usuário executar o clique sobre o controle cujo link foi programado.  Isso pode soar meio estranho para a maioria, mas existem casos em que se programa (erroneamente, diga-se de passagem) o link e o target no evento do usuário, tipo o pressionamento de um botão, e ai, claro a coisa não funciona corretamente.

Desta forma, os melhores lugares para se programar Link e Link Target são os eventos Start, Refresh e Load.  Evitar eventos de usuário, ou seja, aqueles que você programa livremente nos controles da interface, tipo Event &ClienteId.Click ou Event ‘FacaAlgo’. Muitos confundem esse conceito porque no caso dos métodos UDP, CALL, ..., são exatamente nesses eventos que se programam as chamadas.

Vamos aos Exemplos
Confuso? Então vamos aos exemplos práticos. E nesse contexto programei alguns casos que funcionam e outros que não funcionam para que você entenda a diferença.

Em todos o que temos é um WebPanel qualquer com uma imagem isolada ou em um grid, que ao ser pressionada, objetiva-se abrir um relatório PDF definida em uma tal Procedure1.  Passa-se um parâmetro numérico para essa Procedure1 cujo valor é apresentado.

1) Links dinâmicos
Nesse caso, observe que o Link Target foi definido em uma imagem (Bitmap) que foi incluída em um Grid, para se abrir em uma nova janela, e o evento Load é utilizado para se definir o parâmetro a ser passado para a Procedure1 a ser aberta.  

Event Start
    &imagem.LinkTarget = 'blank'
    &imagem = ActionUpdate.Link()
EndEvent

Event Load
    for &i=1 to 10
         &imagem.Link = Procedure1.Link(&i)
         load
    endfor
EndEvent

Nesse caso quando se clica na imagem abre-se uma nova janela com o PDF definido na Procedure1, mostrando-se o valor definido de &i.

2) Link Estático

Programando as propriedades do Link e Link Target, com valores fixos e pré-determinados. Como foi definido no evento Start, esse processo funcionará porque essas propriedades já estarão programadas na interface do usuário.

Event Start
    image1.LinkTarget     = 'blank'
    image1.Link = Procedure1.Link(12)
EndEvent


Observe que no exemplo acima o que temos é um controle Image isolado na WebPanel1, não mais uma imagem em um Grid.

3) Link Target que não funciona

A programação do Link Target está correta, mas observe que foi programado um chamado Link para a Procedure1 no evento, e não se está utilizando a propriedade do controle Image1, portanto, a chamada será no estilo Link tradicional e uma nova janela não aberta.

Event Start
    image1.LinkTarget     = 'blank'
EndEvent

Event Image1.Click
    Procedure1.Link(12)
EndEvent

O mesmo ocorre no exemplo a seguir.

Event Image1.Click
    image1.LinkTarget     = 'blank'
    Procedure1.Link(12)
EndEvent

E o exemplo a seguir também não funcionaria, e a Procedure1 nem seria chamada, uma vez que a definição da propriedade link somente é realizada quando o usuário clica na imagem.

Event Image1.Click
    image1.LinkTarget     = 'blank'
    image1.Link = Procedure1.Link(12)
EndEvent

Entenda que essas propriedades seriam efetivas somente quando o usuário pressiona sobre a Image1, o evento ao link seria programado na próxima chamada, mas mesmo assim não funcionaria corretamente.

4) Janelas em outros estilos

Nos exemplos apresentados anteriormente objetivava-se abrir uma nova janela no navegador, mas muitos não apreciam esse estilo, preferem abrir janelas do tipo Popup.  Então para os mais exigentes temos ai dois exemplos simples.

Nesse primeiro o que temos é uma janela estilo Popup modal com a abertura do relatório PDF definido na Procedure1.

Event Image1.Click
    &window.Object = Procedure1.create()
    &window.Height = 500
    &window.Width  = 500
    &window.Open()
EndEvent

E no próximo e último exemplo temos uma chamada Popup tradicional, que também abre uma janela modal, mas ao contrário do exemplo anterior não possibilita o dimensionamento correto de PDF´s.

Event Image1.Click
     Procedure1.Popup()
EndEvent

Finalizando
Simples e fácil, somente um pouco de atenção no momento da programação. Mas cuidado, não substitua todos os seus Call´s e Udp´s por Link´s, pois os primeiros são chamadas internas de processos e o Link chamadas externas com URL, ou seja, a menos que você goste de sair passeando pela Web, é sempre melhor chamar os objetos no mesmo ciclo interno de processamento.