Genexus 9 vs. Funções externas Java

 

Buenas…

Demorei um pouco, mas estou de volta. Hoje quero falar um pouco sobre funções externas, mais especificamente utilizando GeneXus 9, já que a versão X nos possibilita fazer isso de forma transparente…

Resumidamente, o que se deve fazer é:

1) Personalizar uma classe externa, para que o genexus consiga chamar o método execute() de forma transparente;
2) Compilar a classe externa na mesma package da aplicação;
3) Adicionar o call() no objeto genexus;

Vamos aos detalhes:

1)  Personalizar a classe externa:

Crie uma classe externa java, a que eu montei é uma classe para compactação de arquivos utilizando métodos nativos do java (Olhar no final desse post). O grande segredo aqui são 3 coisas:

  1. Ter um construtor específico que serve para o genexus utilizá-lo quando for instanciar o objeto.
  2. Ter um método execute(), que o genexus irá utilizar para realizar a chamada de fato.
  3. Ter um package name compatível com a aplicação, pois facilita a compilação tanto da classe externa quanto da aplicação genexus, visto que para essa última a classe já está automaticamente adicionada.

 

2) Compilar a classe externa:

Para compilar a classe externa é necessário colocá-la no mesmo diretório onde estão as demais classes geradas da aplicação (normalmente dentro do diretório da KB\diretório do modelo\web, levar em conta que se estiver utilizando um package name terá mais um ou dois subdiretórios dentro de web\). Após feito isso, utiliza-se o mesmo método que o genexus utiliza para compilá-las, ou seja:

  1. Abrir um prompt do DOS e posicioná-lo na pasta web\ do modelo da KB. Como o exemplo feito na minha KB:
    • Iniciar, Executar, CMD ;
    • D: ;
    • Cd D:\Projetos\MinhaKB\Data002\Web;
  2. Configurar a variável CLASSPATH do Java (disponível no menu de execução do GeneXus):
    • SET CLASSPATH=gxclassr.zip;GxUtils.jar;.;
  3. Executar:
    • callmake.bat “C:\Program Files\ARTech\GeneXus\GeneXus90\gxjava\GXJMake.exe” “C:\Program Files\Java\jdk1.6.0_16\bin\javac.exe” gxzip com\genexus\ -O

sendo

    • c:\Program Files\ARTech\GeneXus\GeneXus90 o caminho onde está o genexus 9 na minha máquina e
    • c:\Program Files\Java\Jdk1.6.0_16\ o caminho onde está o JDK.
    • gxzip: o nome da minha classe externa (arquivo .java)
    • com\genexus: o “package name” da minha aplicação.

E, finalmente,

 

3) Adicionar a chamada ao genexus

Essa é a parte mais simples, localize o evento onde deseja-se adicionar a chamada e inclua:

  • &Origem (string) = caminho absoluto de uma pasta ou arquivo a ser compactados;
    • Se for um arquivo, o .zip conterá somente esse arquivo.
    • Se for uma pasta, o .zip conterá todos os arquivos na pasta citada, com exceção de:
      • subpastas;
      • arquivos com extensão .zip, .7z e .jar
  • &Destino (String) = caminho absoluto para o arquivo .zip a ser gerado, se já existir será sobrescrito;
  • Call(‘gxzip’,&Origem, &Destino)

 

Bom, por hoje é só, espero ter sido claro como a água do rio Tietê e discreto como um elefante em uma loja de cristais… hehehe

Qualquer coisa não exite em não me chamar…

Um abraço e boa noite…

/*
               File: GXZip
        Description: Classe para compactação
             Author: Sandro M. Vianna
         Created on: 29/09/2010 16:24:55.75

*/

package com.genexus ;
import java.io.*;
import java.util.zip.*;
import com.genexus.*;

public class  gxzip {

    static final int BUFFER = 2048;

        //Esse construtor vazio é para ser utilizado pelo método main()
	public gxzip()
	{
	}

        //Aqui está o primeiro segredo, é necessário ter um construtor com exatamente esses parâmetros,
        //para que o genexus consiga "enxergar" como uma classe dele
	public gxzip(int remoteHandle, ModelContext context)
	{
	}

    //Deixei o método main para que a classe possa ser chamada pela linha de comandos,
    //Mas é completamente opcional...
    public static void main(String[] args) {
        if (args.length != 2) {
            System.out.println(
   "Usar: java gxzip <arquivos> <novo arquivo compactado> ");
            return;
        }
        try {
            String filename = args[0];
            String zipfilename = args[1];
            gxzip list = new gxzip( );
            list.doZip(filename,zipfilename);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

        //Aqui está o segundo segredo, esse método será utilizado no comando call() do gx
        //Aqui se está recebendo duas strings, apesar de serem recebidas como array de string.
        //Se utiliza sempre o indice 0
        public static void execute(String[] gxFiles, String[] gxZipFile ) {
	  try {
	    String filename = gxFiles[0];
            String zipfilename = gxZipFile[0];
            gxzip list = new gxzip( );
            list.doZip(filename,zipfilename);
	  } catch (Exception e) {
            e.printStackTrace();}
	}

        //Esse é o método que realiza de fato a compactação, é chamado tanto do método main() quanto do execute()
	public void doZip(String filename,String zipfilename) {
            try {
		File ft = new File(filename);
		String entryname, foldername = null;
		final String zipfile = zipfilename;

		if (ft.isFile()){
			//Obtenho o nome do arquivo e da pasta
			//int index = filename.lastIndexOf('\\')+1;
			//String entryname = filename.substring(index);
			//String foldername = filename.substring(0,index-1);
			entryname = ft.getName();
			foldername = ft.getParent();
		}else{
			entryname = "";
			foldername = filename;
			int index = filename.lastIndexOf('\\')+1;
			if (index == filename.trim().length()) foldername = foldername.substring(0,index-1);
		}

		//Obtenho os arquivos contidos na pasta
		File f = new File(foldername);
		String files[] = null;

		//Filtros para não carregar subpastas, arquivos compactados, e o próprio .zip
		FilenameFilter filter = new FilenameFilter() {
			public boolean accept(File f, String name) {
			File ftemp = new File(f.getPath()+'\\'+name);
			return !ftemp.isDirectory() &&
				!name.endsWith(".zip") &&
				!name.endsWith(".7z") &&
				!name.endsWith(".jar") &&
				!name.equals(zipfile);
				}
		};

		//Se foi configurado um nome de arquivo como origem, carrego somente ele na listagem
		if (entryname.length() > 0)
		{
			files = new String[1];
			files[0] = entryname;
		}else{
			//Senão, carrego a todos arquivos na pasta.
			files = f.list(filter);
                }

                byte[] buf = new byte[BUFFER];
		BufferedInputStream origin = null;
		ZipOutputStream s = new ZipOutputStream((OutputStream)new FileOutputStream(zipfilename));

                for (int i=0; i<files.length; i++) {

	        	FileInputStream fis = new FileInputStream(foldername+'\\'+files[i]);
         		origin = new BufferedInputStream(fis, BUFFER);
			s.setLevel(6);
			ZipEntry entry = new ZipEntry(files[i]);
			s.putNextEntry(entry);
			int count;
			while((count = origin.read(buf, 0, BUFFER)) != -1) {
				s.write(buf, 0, count);
			}
			origin.close();
		}
		s.finish();
		s.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
Anúncios

Comparação de XPZ’s e KB’s

Bom dia!

À partir da versão 9.0 do GeneXus, a artech disponibilizou uma ferramenta de comparação, que pode ser executada (até então) somente pelo menu de consolidação de conhecimento (Knowledge Manager, Consolidate, botão Compare).

O que esse botão faz? Basicamente duas coisas:

  1. Distribui TODOS os objetos da KB atual
  2. Compara o XPZ a ser consolidado com o XPZ gerado.

O utilitário é muito bom no detalhamento das informações, porém peca no fato de não se poder selecionar as linhas, para copiá-las, por exemplo.

O que descobri é que se você já possui os doiz XPZ’s a serem comparados, existe uma maneira simples de executar esse utilitário “por fora” do Genexus, basicamente o que deve ser feito é :

Executar a linha de comando:

“C:\Program Files\Artech\GeneXus\GeneXus90\Comparer\XmlModelComparer.exe” “C:\Temp\GXx397.tmp.xml” “C:\Temp\XPZ_Full.xpz” Genexus genexus.xml

Supondo que meu GeneXus 9.0 tenha sido instalado em “C:\Program Files\Artech\GeneXus\GeneXus90\”

Como pode ser observado, o primeiro parâmetro é o caminho para o XPZ (ou .xml) da esquerda, o segundo parâmetro é o caminho para o XPZ (ou .xml) da direita e o terceiro e quarto parâmetros são fixos, necessários pelo utilitário.

Voilá!

Descobri também, que para a diferença entre os dois XPZ’s é gerado um terceiro .XML que pode ser aberto para automatizar-se a recuperação dos nomes dos objetos, por exemplo.

Esse .xml estará localizado, por padrão, em C:\Program Files\Artech\GeneXus\GeneXus90\Comparer\diff.xml

Lembrando que esse comparador funcionará para .XPZ’s da versão 9.0, bem possivelmente de versões anteriores, porém, não acredito que funcionará para versões mais recentes (X, X evol. 1).

Também não consegui localizar esse comparador na instalação do GeneXus X…

Bom, fica a dica…

Um abraço e bom final de semana

Bem vindos

Boa noite…

Relutei bastante para criar um Blog, porque sei que não vou ter tempo para dar a atenção que gostaria de dar: Atualizar com freqüência, ver o que as pessoas estão falando, etc… Mas resolvi tentar, não como uma maneira de entrar (ainda que tardia) na “modinha”, até porque não sou disso, mas sim como uma maneira de compartilhar os mais de dez anos de convivência que tenho com a ferramenta.

Ah sim, aqui falarei bastante sobre o GeneXus, que, para quem não conhece, foi designada originalmente para ser uma ferramenta CASE (Computer Aided Software Engineering, ou Engenharia de Software Auxiliada por Computador), mas é mais do que isso, ele pode ser considerado até como um seguro contra evolução tecnológica (frase que escutei muito do meu amigo e guru Daniel Strack).

O que ele  faz? Para que serve? Vou tentar fazer uma analogia, que ainda considero uma das melhores formas de se explicar algo:

Imagine que você tenha que construir uma casa, essa casa poderá ser para você ou não, como método mais próximo a realidade do mercado de softwares, vamos concordar que, em uma empresa no mercado, 90% das vezes você estará construindo casas para outras pessoas (seus clientes).
Você então terá que montar um projeto onde terá recursos (humanos, materiais), prazo, orçamento, e um escopo (a casa em si).

Agora imagine que, no desenvolvimento de software tradicional (analogamente falando), você construa a casa da maneira que todos conhecem: Encaixando tijolo por tijolo, onde, por exemplo, 4 pessoas se encarregarão de levantar quatro paredes. Para elas fazerem isso, cada uma delas terá que ler um documento dizendo exatamente o que elas devem fazer, vamos supor que elas deverão:

  • Montar os tijolos sob uma superfície, com massa entre o espaçamento de 2 cm entre cada tijolo;
  • Passar uma camada de massa sobre todos os tijolos; E assim por diante até que a parede esteja completa; Fazendo isso terão que:
  • Passar mais uma camada de salpique em toda a parede, e, para finalizar:
  • Uma camada de reboco, também em toda a parede.

Podemos afirmar então que cada uma dessas 4 pessoas utilizaram um método, ou tecnologia, na linguagem de software, para construir as paredes.

Agora, na mesma analogia, com o GeneXus, utilizando a mesma tecnologia, não sejam necessárias 4 pessoas, e sim uma somente e essa pessoa não montaria tijolo por tijolo, massa por massa, salpique, reboco, ela simplesmente declararia algo assim:

  • Parede de tijolos (Casa,10, 3, 4); onde Casa seria o objeto composto pelas 4 paredes conectadas, 10 seria a largura, 3 a altura e 4 a quantidade de paredes.
  • Salpicar paredes (Casa); e, finalmente,
  • Rebocar paredes (Casa);

Declarando isso ela usaria uma ferramenta que automaticamente montaria todos os tijolos, passaria a massa, conectaria as quatro paredes, aplicaria o salpique e o reboco;

Diante dessa analogia podemos contatar alguns fatos:

1) O intelecto necessário para realizar a tarefa de subir as paredes é diferente, na metodologia tradicional seriam necessários 4 pedreiros, com o Genexus é necessário um engenheiro.

2) O fator tempo é algo extremamente diferente, o tempo que as 4 pessoas demorariam para subir as 4 paredes, é aproximadamente o dobro que uma pessoa levaria utilizando o GeneXus.

3) o fator custo (tanto o custo final quanto o custo do projeto), por conseqüência também é severamente afetado pela suposição acima.

4) Agora supondo que surgiu uma nova maneira (tecnologia) para se construir paredes, onde torna-se necessário treinar toda a equipe novamente (isso é BEM comum no desenvolvimento tradicional) e essa equipe terá que esquecer tudo o que aprendeu e aprender novamente. Com o GeneXus não é necessário re-treinar a equipe, pois o engenheiro irá continuar declarando paredes da mesma maneira. O Genexus sim terá que ser atualizado para essa nova tecnologia, e, nesses 10 anos que venho acompanhando, ele sempre o fez, com maestria e as vezes antes mesmo da tecnologia ser disponibilizada publicamente (.NET Early Adoption é um exemplo, em outro post irei comentar sobre a demonstração dos engenheiros de software da ARTech em um evento da Microsoft). Atualizado o “motor” do GeneXus, tudo pronto…

5) Supondo agora que existe uma reforma a ser feita na casa, e será necessário destruir uma parede e construir duas novas…Bom… acho que já alcancei o ponto, não??? Somente para constar o GeneXus costuma ser 20 vezes mais rápido na manutenção do que no desenvolvimento comum…

Alguns pontos chaves que considero interessante da ferramenta:

  • Geração de código 100% automática;
  • Geração de scripts de criação e alteração da base de dados 100% automático;
  • Programação declarativa;
  • Multiplataforma;
  • Sem runtime (gera código 100% nativo da linguagem);
  • Baseado em desenvolvimento incremental;

Bom, aos leigos, sejam bem vindos ao mundo GeneXus, aos que já conhecem, em breve estarei “postando” algo interessante, e também estou aberto a sugestões, sempre, afinal, foi a comunidade GeneXus o maior coadjuvante para o crescimento da ferramenta…

Para mais detalhes:

http://www.genexus.com/portal/hgxpp001.aspx?2,61,1006,O,P,0,MNU;E;226;1;236;2;MNU;,

http://www.gxtechnical.com/

Um abraço e até a próxima…