segunda-feira, 25 de março de 2013

Genexus - Capturar Blob File Name

Quando trabalhamos com arquivos do tipo Blob (Binay large object), nos deparamos com situações onde devemos armazenar, em atributos ou variáveis, o nome e a extensão original do arquivo informado.

Trabalhando com Atributos

Ao trabalharmos com atributos isso pode ser realizado de uma forma bem simples. Por exemplo, em uma transação teremos 3 variáveis:
  1. File - blob;
  2. FileName - varchar(40);
  3. FileType - varchar(5);
Para gravarmos o nome e a extensão original do arquivo selecionado pelo usuário, devemos definir nas propriedades do atributo File (blob) as seguintes características:

Genexus Blob

Trabalhando com Variáveis

Um dos problemas em se trabalhar com variáveis do tipo Blob, é a falta de uma função para capturarmos o nome original do arquivo.

Por exemplo, quando o usuário da nossa aplicação deseja enviar algum arquivo via FTP ou Email, somos obrigados a gravar este arquivo em uma tabela para dessa forma, obtermos o nome original deste. Caso essa gravação não seja realizada, o arquivo enviado pelo usuário, automaticamente, é aberto na pasta "Temp media directory", que por padrão é a pasta "PublicTempStorage", e, recebe um nome aleatório.

Neste post irei demonstrar como podemos obter o nome original deste arquivo através da biblioteca Jquery.

Em uma Web Panel, adicionei à tela, duas variáveis e um botão. As variáveis definidas foram:
  1. &Blob - blob;
  2. &FileName - Varchar(40)
Agora precisamos programar a função em Jquery que irá executar esta captura do nome original. Para isso, utilizei a função "blur". Esta função é justamente o oposto da função "focus", ou seja, quando a variável blob perder o foco, o procedimento irá se executar. Vejamos:

Event Start
//=====Adiciona a biblioteca Jquery=====
Form.JScriptSrc.Add('http://code.jquery.com/jquery-latest.js">')

//=====Inicio do Script=====
Form.HeaderRawHTML = '<script type="text/javascript">'
Form.HeaderRawHTML += '$(document).ready(function(){'

//=====Quando a variável Blob perder o foco, executa=====
Form.HeaderRawHTML += '$("#vBLOB").blur(function(){'
Form.HeaderRawHTML += 'var nome = $("#vBLOB").val();'
Form.HeaderRawHTML += 'nome = nome.match(/[-_\w]+[.][\w]+$/i)[0];'

//=====Define o valor da variavel File name=====
Form.HeaderRawHTML += '$("#vFILENAME").val(nome);'
Form.HeaderRawHTML += '});'
Form.HeaderRawHTML += '});'
Form.HeaderRawHTML += '</script>'
EndEvent

Mais uma ótima utilização de Jquery, qualquer dúvida o email genexus@outlook.com é ótimo para receber qualquer coisa. Abraço.

segunda-feira, 18 de março de 2013

Genexus FTP - Envio e Recebimento de Arquivos

Nesta matéria irei demonstrar como podemos realizar o envio e o recebimento de arquivos via FTP através de funções do Genexus.

Para atingir este objetivo, vou utilizar, primeiramente para o envio de arquivos, um objeto web panel, onde irei adicionar uma variável blob, capaz de "guardar" um arquivo e, a partir de um botão, realizar o envio deste arquivo para um servidor FTP previamente configurado em uma transação de parâmetros da aplicação.

Após, irei demonstrar como realizar o recebimento deste arquivo salvo no servidor FTP. Com isso podemos até trabalhar com este arquivo, ou então gravá-lo em uma tabela da aplicação.

Funções FTP

O Genexus possui funções FTP pouco conhecidas, ou difundidas... Estas funções não se encontram na biblioteca de funções do software (Menu Insert Function), e mesmo quando digitamos estas funções, ao buscar a tecla de atalho (CTRL + Espaço) elas não são mostradas!

O Genexus disponibiliza 7 funções FTP ao total, estas funções nos permitem desde programar uma conexão a um servidor, quanto excluir arquivos presentes neste servidor. 

Uma função que o genexus não disponibiliza, mas que seria muito importante, é algum método de listar todos os arquivos e pastas presentes no servidor FTP. Para isso devemos utilizar a linguagem ambiente .NET ou Java, mas isso veremos em um outro tópico.

Ao longo dos exemplos irei utilizar e explicar todas estas funções.

Conectando a um Servidor FTP

Bom, para começarmos, primeiro necessitamos de um servidor FTP. Para demonstrar irei imaginar um servidor ftp, seu usuário e senha, isso pois não consegui achar um servidor público que permita realizar o dowload e o upload de arquivos.

As variáveis utilizadas poderão ser recebidas como parâmetros nos objetos.

Vamos então realizar a conexão:

//=====Definindo valores das variáveis=====
&Host = 'ftp.genexus.com'
&Usuario = 'Admin'
&Senha = '123456'

//=====Conexão com o Servidor (Host)=====
Call("GxFtpCon", &Host, &Usuario, &Senha)

//=====Verifica se a conexão foi realizado com sucesso=====
Call("GxFtpError", &Retorno)

//===== Retorno 1 - erro ao conectar=====
if &Retorno = 1
//=====Captura mensagem de erro e exibe na tela=====
Call("GxFtpStat",&Mensagem)
msg('Erro: '+&Mensagem)
else
//=====Retorno 0 - conectado com sucesso=====
msg('Conectado com sucesso')
endif

//=====Realiza Logoff do Servidor FTP=====
Call("GxFtpDis")

Enviando Arquivos a um Servidor FTP

Após realizarmos a conexão a um servidor, a partir de funções do Genexus teremos uma possibilidade de 3 ações a serem tomadas: o envio de arquivos, o recebimento e a exclusão destes.

Vamos começar enviando um arquivo determinado por um usuário da aplicação, através de uma variável blob presente em um objeto web panel.

Para isso, primeiro precisamos desenhar a nossa web panel, de forma bem simples será necessário incluirmos uma variável blob e um botão. Este botão irá chamar a nossa procedure de envio de arquivos, enviando como parâmetro o link do arquivo definido pelo usuário, da seguinte forma:

Event Enter
if &Blob.IsEmpty()
msg('Selecione um arquivo!')
else
ConexaoFTP.Call(&Blob.ToString())
endif
EndEvent

Em nossa procedure, iremos programar o envio do arquivo após a conexão com o servidor FTP. Esta função de envio recebe 3 parâmetros:
  1. Source do arquivo, caminho do arquivo físico, este arquivo deverá estar presente no servidor de hospedagem da aplicação;
  2. Local a ser salvo no servidor FTP. Diretório e nome que será atribuído ao arquivo quando este for enviado ao servidor. Quando apenas o diretório seja informado, o nome permanecerá o mesmo.
  3. Modo de envio, poderá ser ASCII ou Binario. Irei determinar ASCII, mas cada tipo de arquivo possui uma opção ideial. Pesquise para encontrar aquele melhor para o seu caso.
Logo, nossa programação ficará da seguinte forma, em rules:

//=====Caminho físico do arquivo - Varchar(400)=====
parm(in:&SourceArquivo);

Em Source:
&Host = 'ftp.genexus.com'
&Usuario = 'Admin'
&Senha = '123456'
&Diretorio = 'ArquivosEnviados\'

Call("GxFtpCon", &Host, &Usuario, &Senha)
Call("GxFtpError", &Retorno)

if &Retorno = 1
Call("GxFtpStat",&Mensagem)
msg('Erro: '+&Mensagem)
else
msg('Conectado com sucesso')

//=====Realiza o envio de um arquivo para o Servidor=====
// Modo "A" = Ascii "B" = Binario
Call("GxFtpPut", &SourceArquivo, &Diretorio, "A")

//=====Verifica se ocorreu algum erro=====
Call("GxFtpError", &Retorno)
if &Retorno = 1

//=====Captura mensagem de erro e exibe na tela=====
Call("GxFtpStat",&Mensagem)
msg('Erro: '+&Mensagem)
else
msg('Arquivo enviado com sucesso!')
endif
endif

Call("GxFtpDis")

Download e Exclusão de arquivos do Servidor FTP

Bom, por fim vamos visualizar como realizar o download de um arquivo e consequentemente a sua exclusão do servidor FTP.

Assim como a função de Upload, a função de download receberá 3 parâmetros:
  1. Source do arquivo presente no servidor FTP, diretório e nome;
  2. Destino do download, se apenas o diretório for determinado, o arquivo manterá o nome original;
  3. Modo de recebimento, "A" = ASCII, "B" = Binario;

Neste exemplo não precisaremos da nossa web panel, logo, em uma procedure programe os eventos da seguinte forma:

&Host = 'ftp.genexus.com'
&Usuario = 'Admin'
&Senha = '123456'
&SourceArquivo = 'ArquivosEnviados\teste.txt'
&DiretorioDestino = 'C:\Temp\'

Call("GxFtpCon", &Host, &Usuario, &Senha)
Call("GxFtpError", &Retorno)

if &Retorno = 1
Call("GxFtpStat",&Mensagem)
msg('Erro: '+&Mensagem)
else
msg('Conectado com sucesso')

//=====Realiza o download de um arquivo para o Servidor=====
// Modo "A" = Ascii "B" = Binario
Call("GxFtpGet",&SourceArquivo,&DiretorioDestino, "A")

//=====Verifica se ocorreu algum erro=====
Call("GxFtpError", &Retorno)
if &Retorno = 1

//=====Captura mensagem de erro e exibe na tela=====
Call("GxFtpStat",&Mensagem)
msg('Erro: '+&Mensagem)
else
msg('Arquivo recebido com sucesso!')

//=====Realiza a exclusão do arquivo no servidor FTP=====
Call("GxFtpDelete",&SourceArquivo)

//=====Verifica se ocorreu algum erro=====
Call("GxFtpError", &Retorno)
if &Retorno = 1

//=====Captura mensagem de erro e exibe na tela=====
Call("GxFtpStat",&Mensagem)
msg('Erro: '+&Mensagem)
else
msg('Arquivo excluído com sucesso!')
endif
endif
endif

Call("GxFtpDis")

sábado, 2 de março de 2013

Configuração de Servidores - Erro no envio de emails

Configuração Servidor
Uma das dificuldades de se trabalhar com aplicações web, são as configurações dos servidores, seja de produção ou homologação.

Quando iniciamos com o Genexus, temos um desafio inicial, que é correta configuração do ambiente, tanto para compilar aplicações em Java quando em .Net. Após esta configuração inicial, do ambiente de desenvolvimento, temos um outro desafio: A configuração dos servidores de produção e homologação. 

Esta tarefa se torna árdua em virtude das "N" combinações possíveis de ambiente. Podemos trabalhar com SQL Server 2005 em um servidor Windows Server 2003, 32 bits, ou talvez com Postgresql em um sistemos operacional Windows Server 2008 64 bits. Além destas possíveis combinações, temos as diferentes versões  do Genexus. Tudo isso combinado, se torna um pesadelo para qualquer profissional da TI.

Bom pessoal, vou compartilhar um erro que enfrentei nesta última semana. Estou trabalhando em um projeto na versão do Genexus Upgrade 2, ao publicar o sistema em um ambiente Windows Server 2008 64 bits, enfrentei uma dificuldade nos envios de email pela aplicação.

Independente da configuração do firewall, ele podia inclusive estar desligado, e das portas configuradas através da programação da procedure, eu sempre recebia a mesma mensagem:

"An error occurs while communicating with the remote host."

Esta mensagem aparecia logo na hora de realizar o login junto ao host. Cheguei inclusive, a dar privilégios totais de segurança para o usuário IIS, isso, para verificar se era alguma configuração do servidor. Porém, mesmo assim, nada disso trouxe um efeito positivo.

Após algumas pesquisas e pesquisas, encontrei um post de um usuário, isso em 2010, onde este, afirma ter encontrado um bug ao realizar envios  de emails em um servidor Windows 7 64 bits, este usuário estava programando na versão Upgrads 2 do genexus, a mesma que a minha.

Segundo a artech, este bug foi corrigido na versão Upgrade 7, logo, as outras versões devem apresentar o mesmo problema.
E qual a solução proposta?

Encontrei no blog Genexando, uma rotina de envio de email em CSharp, a ser implementada no genexus. Esta programação contorna o problema, porém restringe a aplicação para um único gerador, caso deseja compliar em Java, deverá criar a mesma rotina em Java.

Vamos lá pra o código. Criei um objeto Procedure no Genexus, e em Source programe:
//=====Variáveis utilizadas - poderão ser recebidas como parâmetros=====

//=====Host de conexão - Varchar(40)=====
&SMTPHost = 'smtp.gmail.com.br'

//=====Usuário e senha de conexão -Varchar(40)=====
&SMTPUserName = 'Usuario'
&SMTPEmailPassword = 'senha'

//=====Enviar o email para... - Varchar(40)=====
&EMailTo = 'edu_ferroni@hotmail.com'

//=====Assunto - Varchar(40) e Mensagem - LongVarchar=====
&EMailSubject = 'Assunto'
&EMailMessage = 'Mensagem'

//=====Código nativo CSharp=====
csharp try
csharp {
csharp System.Net.Mail.MailMessage mM = new System.Net.Mail.MailMessage();

csharp mM.From = new System.Net.Mail.MailAddress([!&SMTPUserName!]);
csharp mM.To.Add([!&EMailTo!]);
csharp mM.Subject = [!&EMailSubject!];
csharp mM.Body = [!&EMailMessage!];
csharp mM.IsBodyHtml = true;
csharp mM.Priority = System.Net.Mail.MailPriority.High;

//=====Porta de conexão utilizada: 587=====
csharp System.Net.Mail.SmtpClient sC = new System.Net.Mail.SmtpClient([!&SMTPHost!], 587);
csharp string strId;
csharp string strPassword;
csharp strId = [!&SMTPUserName!];
csharp strPassword = [!&SMTPEmailPassword!];
csharp sC.Credentials = new System.Net.NetworkCredential(strId, strPassword);
csharp sC.Send(mM);

//=====Verifica status: 1 = envio com sucesso; 0 = erro ao enviar=====
csharp [!&statusEnvio!] = 1;
csharp }
csharp catch (System.Exception ex)
csharp {
csharp [!&statusEnvio!] = 0;
csharp }

Agradeço ao Genexando pelo código, me ajudou bastante, e espero que ajude a quem mais precisar.

Com o tempo irei postar mais sobre este assunto, configuração de ambientes. Irá inclusive, me ajudar a documentar os processos que venho passando.

Grande abraço.