Generando Código: Hello World con AjGenesis


Mi proyecto preferido, AjGenesis, consiste en un generador de código, escrito en VB.NET. Es un proyecto de código abierto, con una licencia tipo BSD, que permite utilizarlo en cualquier proyecto que quieran. Se puede usar como librería, invocado desde nuestro proyecto, se puede invocar desde la línea de comando, o puede ser utilizado desde el poderoso NAnt (esto último me permitió organizar mejor las tareas que realiza el generador de código).


En la página del proyecto (y en el proyecto mismo) hay multitud de ejemplos, que generan código desde un modelo, usando plantillas. Los ejemplos generan código PHP, Java, JSP, VB.NET, C#, ASP.NET, y hasta scripts de base de datos y procedimientos almacenados. Quisiera destacar dos puntos:


- El modelo del que parte es totalmente definible por el usuario


- Las tareas y plantillas a aplicar son totalmente programables y controlables


Esto lo diferencia de otros generadores. Ud. puede hacerse su propio modelo, y sus propias plantillas, para generar los artefactos de texto que prefiera. Otros sistemas parten de la base de datos, y sólo generan un grupo de artefactos de textos predefinidos (por ejemplo, POJOs, o DAOs). Pero con AjGenesis puede generar lo que Ud. quiera.


Para ejemplificar, este artículo se dedica a modelar algo que, si bien no es lo último en tecnología, es la primera prueba que debe pasar un generador de código: modelar y generar un viejo pero entrañable “Hello, World” (programa que encontré por primera vez en el venerable “The C Programming Language” de los buenos de Kernighan y Ritchie).


Los archivos de este ejemplo, pueden bajarse de HelloWorld1.zip


Primero, el modelo. Como menciono en mis charlas, el modelo es una simplificación de la realidad. El modelo, por ejemplo, un mapa, no es la realidad, el territorio. En el caso de los modelos de AjGenesis, se trata de crear inicialmente, un modelo que muestre lo variable de nuestro sistema. En el caso de un HelloWorld, lo que quisierámos modelar como variable, es el mensaje. Entonces, creamos en un directorio de trabajo, el archivo Project.xml:


<Project>
<Message>Hello World, by AjGenesis</Message>
</Project>


Este es el primer paso. Vean que no tuvimos que usar un modelo predefinido, simplemente, lo escribimos en un documento XML bien formado. Nada de schemas, nada DTDs, o bichos raros. Solamente nuestra creatividad.


El segundo paso es elegir la tecnología (lenguaje, plataforma, framework, base de datos), que vamos a utilizar, y escribir (o reutilizar) plantillas. Decidimos crear un ejemplo en VB.NET, un simple programa de consola. La plantilla la escribimos en el archivo HelloVb.tpl



‘ Hello World demo
‘ generated by AjGenesis
http://www.ajlopez.com/ajgenesis


Module HelloWorld
 Public Sub Main()
  System.Console.WriteLine(“${Project.Message}”)
 End Sub
End Module


Acá aparece una característica de las plantillas: permiten acceder y utilizar en la salida, los datos del modelo. Al escribir Project.Message entre ${ y }, le indicaros al procesador AjGenesis, que cuando trabaje sobre esta plantilla, reemplace ese texto por el valor de la rama Project/Message en nuestro modelo. Vemos que no usamos una notación XML o XPath para referirnos a algo del modelo. El modelo inicial está serializado en XML, pero AjGenesis lo levanta a memoria, y nos lo deja como un objeto con propiedades.


Hubiéramos podido escribir el modelo como


<Project Message=”Hello World, by AjGenesis”/>


El modelo en memoria sería el mismo. Aunque ahora Message está como atributo, para nuestra plantilla sigue siendo la propiedad Message del objeto Project.


Ya tenemos el modelo, y la plantilla. Necesitamos bajar y expandir el AjGenesis-0.4.3.zip (versión en desarrollo, las anteriores versiones están en el directorio de fuentes SourceForge del proyecto). En esa versión, hay un directorio bin con librerías y algún ejecutable. El AjGenesis.Console.exe es el programa que puede invocarse para tomar el modelo y la plantilla, y generar un archivo, así:


AjGenesis.Console Project.xml HelloWorldVb.tpl HelloWorld.vb


Los parámetros se explican así:


Archivo .xml: cuando encuentra en la lista de parámetros un archivo XML, AjGenesis lo carga en su ambiente de variables. El nodo inicial del XML pasa a ser el nombre de la variable que contiene al modelo.


Archivo .tpl: lo toma como plantilla, y lo procesa, generando un archivo con el nombre del siguiente parámetro.


Por supuesto, para que esto funcione, o deberemos poner la ruta completa del ejecutable AjGenesis.Console, o deberemos incluir el directorio bin de AjGenesis en el PATH de nuestro ambiente.


Los parámetros los procesa en orden. Podríamos poner más de un modelo, más de un archivo XML. Por ejemplo, un segundo archivo XML podría describir la tecnología de base de datos a usar, o el nombre de la empresa que está usando el modelo, o cualquier otra cosa que se nos ocurra. Sería conveniente en este caso que el segundo archivo XML tenga un nodo raíz distinto de Project, porque así no sobreescribe al modelo del anterior archivo. También podríamos colocar varios archivos de plantilla con su correspondiente archivo resultado, en una misma invocación.


Si ejecutamos entonces el comando de arriba (necesitamos un framework .NET instalado, recordemos que AjGenesis está escrito en .NET), se genera el archivo HelloWorld.vb



‘ Hello World demo
‘ generated by AjGenesis
http://www.ajlopez.com/ajgenesis


Module HelloWorld
 Public Sub Main()
  System.Console.WriteLine(“Hello World, by AjGenesis”)
 End Sub
End Module


No vamos a decir “Uy que bruto..”, pero es el primer paso.


Pero vayamos más alla. Supongamos que ahora, con el mismo modelo, queremos generar nuestro gran sistema HelloWorld, en Java. Las presiones del mercado, nuestros clientes, nos piden la nueva versión en el lenguaje multiplataforma Java, y nosotros estamos acá para servirlos. Bien, manos a la obra, creamos un archivo HelloWorldJava.tpl con


/**
* Hello World demo
* generated by AjGenesis
* http://www.ajlopez.com/ajgenesis
*/


public class HelloWorld {
 public static void main(String [] args) {
  System.out.println(“${Project.Message}”);
 }
}


y ejecutamos en la línea de comando

AjGenesis.Console Project.xml HelloWorldJava.tpl HelloWorld.java

y voilá, se genera el archivo HelloWorld.java:


/**
* Hello World demo
* generated by AjGenesis
* http://www.ajlopez.com/ajgenesis
*/


public class HelloWorld {
 public static void main(String [] args) {
  System.out.println(“Hello World, by AjGenesis”);
 }
}


Ya estamos cebados. Vamos por un ejemplo más flexible. Quisiéramos ahora generar el programa VB.NET, el programa C#, el programa Java, y que el nombre de la clase, del programa, sea algo variable (en las plantillas anteriores aparecía siempre HelloWorld como nombre del archivo y de la clase o módulo).


Los archivos de este segundo ejemplo se pueden bajar de HelloWorld2.zip.


Para esto, en otro directorio, creamos el archivo Project.xml con el contenido


<Project>
 <Name>HelloWorld</Name>
 <Description>Hello World Demostration</Description>
 <Message>Hello World, by AjGenesis</Message>
</Project>


Y escribimos las plantillas ModuleVb.tpl



‘ ${Project.Description}
‘ generated by AjGenesis
http://www.ajlopez.com/ajgenesis


Module ${Project.Name}
 Public Sub Main()
  System.Console.WriteLine(“${Project.Message}”)
 End Sub
End Module


y ClassJava.tpl


/**
* ${Project.Description}
* generated by AjGenesis
* http://www.ajlopez.com/ajgenesis
*/


public class ${Project.Name} {
 public static void main(String [] args) {
  System.out.println(“${Project.Message}”);
 }
}


Estudiemos otra característica de AjGenesis: la capacidad de ejecutar un script, en un lenguaje denominado informalmente AjBasic. Creo que esta es una característica poderosa, porque posibilita ir más allá de simplemente la línea de comando. Nos permite manipular programáticamente el modelo y las tareas a realizar. En los ejemplos que encontrarán en la página del proyecto, se usa mucho esta característica, llegándose a producir soluciones completas, con decenas de archivos. Pero veamos nuestro ejemplo.


El programa lo ingresamos en el archivo Build.ajg


PrintLine “Generating ${Project.Name}”


TransformerManager.Transform(“ModuleVb.tpl”, “${Project.Name}.vb”, Environment)
TransformerManager.Transform(“ClassJava.tpl”,”${Project.Name}.java”, Environment)


El lenguaje AjBasic, tiene algún verbo predefinido, como el autodescriptivo PrintLine. Notemos que, como en otros lenguajes de scripting, tiene expansión de expresiones en los strings. Esto es, cuando en un texto entre doble comillas (una constante string), ubica una expresión entre ${ y }, la evalúa y la reemplaza por el valor resultante. Muchos de Uds. reconoceran aquí una conducta similar a otros lenguajes de scripting de Unix/Linux, o a PHP, o al Expression Language de JSP 2.x.


La variable TransformerManager es una de las pocas predefinidas. No he definido muchas, y Uds. pueden agregar variables al ambiente de AjGenesis. Pero TransformerManager sirve para invocar programáticamente lo que hacemos desde la línea de comando. Así, el primer parámetro de su método Transform el archivo plantilla, el segundo parámetro es el archivo a generar, y el tercero, la colección de variables definida (en el ejemplo usamos Environment, otra de las variables predefinidas, que justamente es el diccionario de variables que ahora están disponibles en la evaluación de este script).


Ejecutamos lo anterior con


AjGenesis.Console Project.xml Build.ajg


El programa de consola está preparado para ejecutar cada parámetro que tenga la extensión .ajg, interpretándolo como un texto AjBasic.


Pero podemos ir más allá. El año pasado (el proyecto AjGenesis ya lleva sus años en desarollo), incorporé soporte de NAnt. Esto lo hice escribiendo tareas (Tasks) de AjGenesis que pueden invocarse desde ese gran utilitario. Yo uso además, el utilitario NAnt-GUI para ejecutar los archivos .build desde una ventana gráfica.


Escribamos un archivo default.build con el contenido (revise y modifique la property ajgenesis.dir para que refleje el directorio donde ha dejado al AjGenesis):


<?xml version=”1.0″?>
<project name=”Example 1″ default=”build”>
<property name=”ajgenesis.dir” value=”c:/ajlopez/dev/AjGenesis-0.4.3″/>
<property name=”nanttasks.dir” value=”${ajgenesis.dir}/bin”/>


<target name=”clean” description=”cleans build directory”>
   <delete dir=”${build.dir}” verbose=”true” if=”${directory::exists(build.dir)}” />
</target>

<target name=”loadtasks” description=”loads AjGenesis tasks”>
   <loadtasks assembly=”${nanttasks.dir}/AjGenesis.NAnt.dll” />
</target>


<target name=”init” depends=”loadtasks” description=”init the AjGenesis model”>
   <loadmodel model=”Project.xml”/>
</target>


<target name=”build” depends=”init”>
   <executetask task=”Build.ajg”/>
</target>
</project>


Entonces, desde la línea de comando podemos invocar


nant


Si tenemos configurado a ese utilitario, procesa el target default que de build.xml. Yo uso el NAnt-Gui, que me presenta la pantalla



Espero que este artículo les sirva como inicio de explicación a algunas de las características de AjGenesis. Espero escribir un próximo artículo, con ejemplos de uso de AjBasic dentro de las mismas plantillas, uso más intensivo del NAnt, manipulación del modelo en memoria, y generación de aplicaciones completas, en distintas plataformas y tecnologías.


Si alguien le parece útil, les pido que lo difundan, por ejemplo, con artículo de cómo lo están usando, en su blog.


Gracias por todo, nos leemos!


Angel “Java” Lopez
http://www.ajlopez.com/


 

This entry was posted in 1389, 1390, 1391, 2643, 6145. Bookmark the permalink.

12 Responses to Generando Código: Hello World con AjGenesis

  1. anonymouse says:

    Estimado Ángel “java” López,

    no he tenido aún la oportunidad de probar tu producto AjGenesis, pero no puedo dejar de enviarte mi comentario: no podés ponerle tus iniciales al nombre de un producto! Acaso la estaré pifieando y la Aj en AjGenesis responde a: Automatic JJJeneration?? … vamos viejo!, un poco de imaginación … que patético!

  2. lopez says:

    Hola gente!

    Bien, al fin un comentario en este post!!! :-)

    Bueno, la costumbre de poner mis iniciales a un proyecto, viene de cerca de diez anios, asi que ya es una costumbre. En mis charlas, bromeo sobre eso: “este es el ajmundo, el ajlenguaje… :0)…” Pero lo importante creo que es el software y que lo usen o aprendan algo. No se si el AjGenesis conseguira eso, pero es el intento. La imaginacion la pongo eso. Ademas, cuando le ponia otro nombre a mis proyectos, siempre habia un proyecto con un nombre similar, o igual. Asi, que aparecio, creo que alla por el 95, algun ejemplo aj… Y siguio. Aun asi, tengo colision de nombres. Hay por ejemplo, un AjLogo…. snif… :-)

    Mas proyectos aj en http://www.ajlopez.net/Proyectos.php

    Nos leemos!

    Angel “Java” Lopez

    http://www.ajlopez.com/

  3. Diego Maciel says:

    Angel, me estaba preguntando por qué no elegiste la generación de código a partir de un XML generado por ejemplo por UML.

    Me gustaría que AJGénesis pueda trabajar con stándares de la industria, o herramientas que ya manejamos los desarrolladores. Por ejemplo, veo también que usás un lenguaje scripting ajBasic y ya existen lenguajes como Ruby, Groovy, etc.

    Por otro lado no entiendo la estrategia de usar productos con licencia para generar productos open-source. El desarrollo está hecho con VB.NET y más allá de la versión express del Visual Studio a la larga hay que pagar licencia, prefiero trabajar con JAVA.

    Algo que sería interesante y no veo reflejado, es cómo integrás ajGénesis con otros frameworks, como por ejemplo Spring.

    Desde ya saludos cordiales.

  4. lopez says:

    Hola Diego!

    Tanto tiempo!

    Respuestas rapidas, estoy a mil, preparando charlas de GlassFish, Mule, y demas…. Podes compilar el AjGenesis con alguna tarea del NAnt, no hace falta el Visual Studio. El VB.NET me resuelve algunos temas de conversion automaticas de tipos, y ya tenia implementado un interprete que es el AjBasic. Igualmente, como el NAnt, el NHibernate y demas, esta mas pensado para que la gran mayoria de sus usuarios, simplemente lo use, no necesite recompilarlo o adaptarlo. Lo que se necesita trabajar, es por afuera de AjGenesis (su codigo): son los templates.

    El XML XSLT es un camino de ida…. No tenes la capacidad que te da un lenguaje interpretado, de llamar en cualquier momento a lo que quieras, que este por ejemplo, en el framework de .NET. Ya lo vi hace anios, y creeme, respuesta rapida: no sigas ese camino, es muy duro y poco flexible. El camino de tener un lenguaje, me permite implementar decisiones complejas (la idea es que AjGenesis termine usando un sistema experto escrito en AjBasic o lo que sea, para generar lo que el modelo no provee, que tome decisiones como toma un desarrollador, que haya agentes que colaboren, que un agente se convierta en “especialista en Spring”, mientras que otro sea “especialista en usabilidad”, y asi…. y que cada uno colabore a enriquecer el modelo, o lo que se va generando…)

    AjBasic me permite hacer trucos que en otros lenguajes tendria que pelearlos: como encapsular cualquier cosa como un objeto, dinamicamente, etc….. Y como AjBasic esta escrito en .NET, cualquiera lo puede ir a tocar o mejorar, o usar como esta. Fijate igual en mi blog que AjGenesis esta pensado desde abajo, para poder luego ponerle plugins de otros “renderizadores” de texto, no hara falta usar solo AjBasic

    Hmmm…. se integra con Spring, en el mismo sentido en que se “integra” con cualquier cosa que necesite archivos de texto: genera lo que vos quieras, desde configuraciones de Spring, a configuraciones de Struts, y lo que quieras. No es que este “integrado”: es para usar desde afuera de cualquier cosa que existe o que existira en un milenio. Y si queres, lo colgas del NAnt, o de tu aplicacion, y lo invocas.

    Nos leemos!

    Angel “Java” Lopez
    http://www.ajlopez.com/

  5. Mauricio Gelves says:

    Acabo de bajarlo y voy a testearlo a full porque es la herramienta que andaba buscando.

    Suerte Angel…

    Mauricio

  6. Antonino Ferrando says:

    Hola Angel! Creo que mas alla de todos los comentarios que he visto, ninguno fue capaz de felicitarte por todos los aportes que haces a la comunidad de informaticos.

    Te felicito! y gracias, he visto implementar AJGenesis como la herramienta de generacion en una de las empresas donde trabaje y funciono todo de maravillas.

    Un abrazo

    Antonino

  7. Hola AJLopez,

    Muy interesante tu idea de generar código con plantillas. He usado varios generadores de código y casi siempre tienen un talón de aquiles…
    Estoy con todo el entusiasmo de probar AJGenesis. Te escribiré cómo me fue de aquí a un tiempo.

  8. Antonino says:

    Cuando pruebo el ejemplo me da el siguiente error:

    The format of the file ‘AjGenesis.NAnt.dll’ is invalid.

    Que puede estar pasando ??

    Antonino

  9. lopez says:

    Hola Antonino!

    Hmmm… Estas usando NAntGui? Fijate en la version NAnt compilada en BinDeNAntGUIVS2005.rar de los archivos del grupo

    http://groups.google.com/group/codegeneration

    Ahi esta recompilado el NAntGui para que funcione con VS2005, y AjGenesis.

    Si no es eso, preguntaria en ese grupo, donde ya pasaron por ese problema.

    Nos leemos!

    Angel “Java” Lopez
    http://www.ajlopez.com/

  10. Antonino says:

    Ahi parece que anduvo Angel, muchas gracias

  11. ibg says:

    hola angel,

    buscando informacion para mi proyecto me encontre con tu pagina y me parecio muy interesante lo que intentas conseguir.

    Yo tengo k trabajar en un generador de codigo para portlets jsr286 con eventos partiendo desde las anotaciones de Java5. Ando mirando la herramienta apt que me parece que me puede servir.

    Tus ideas siempre parten desde un codigo XML hacia otros codigos o tambien estas trabajando en tomar como base otro tipo de lenguajes

    enhorabuena

  12. Edgard Espinoza says:

    Hola AJ es excelnte el AJGenesis eslo que estaba buscando.

    Po otro lado estube probando el ejemplo HelloWorld2.zip. me sale error cuando lo ejecuto de NANT .GUI.
    Pero cuando le ejecuto desde el bat Make.bat si genera bien
    tu comentario…

    El error es el siguiente:_________________

    Buildfile: file:///…/ajgenesis/HelloWorld2/default.build
    Target framework: Microsoft .NET Framework 1.1
    Target(s) specified: build

    [property] Read-only property “ajgenesis.dir” cannot be overwritten.
    [property] Read-only property “nanttasks.dir” cannot be overwritten.

    loadtasks:

    BUILD FAILED- 0 non-fatal error(s), 2 warning

    …\ajgenesis\HelloWorld2\default.build(11,4):
    Failure scanning “…ajgenesis\AjGenesis-0.5\bin\AjGenesis.NAnt.dll” for extensions.
    The format of the file ‘AjGenesis.NAnt.dll’ is invalid.

    Total time: 0.1 seconds.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>