martes, marzo 21, 2006

Primera compilacion de nuestro proyecto!

Ya compila (gracias vicen por la currada de ver y corregir las petadas de las plantillas)!!! Si sigues el post anterior, veras que es lo que he hecho para compilar a partir de la version que modificaste.

Dicho esto, voy a poner un pantallazo de la primera version compilada del ObjectOrientedMultidimensionalModel (vaya nombrecito, eh? ;).

De momento no podemos hacer conexiones entre Facts, dimensions y base clases, pero poco a poco.

lunes, marzo 20, 2006

Problemas derivados de usar palabras reservadas

Una vez tenemos el DomainModel.dsldm completo y hemos sincronizado el Designer.dsldd (utilizando la herramienta de Modelisoft por ejemplo), llega la hora de pulsar el botoncito de "Transform all templates" , que nos generara el código C# que compilaremos para que se nos cree la libreria de nuestro Lenguaje de Dominio con la que podremos ya empezar a generar nuestro código y nuestras cosas.

Voy a exponer algunos problemas derivados de nuestro modelo de dominio en concreto.

Nuestro proyecto consiste en un Modelo Multidimensional Orientado a Objetos. Se trata de un lenguaje de modelado multidimensional para almacenes de datos. El problema que hemos tenido ha sido por la nomenclatura de nuestras clases. Aqui podeis ver la estructura de nuestro DomainModel.dsldm en la que podemos destacar cosas como la clase "Class" o "Base", cuyas relaciones llamadas "class" y "base" nos van a dar alguna que otra sorpresita desagradable.



Las palabras reservadas, no se pueden usar y eso es algo que todavia al estar en fase beta, las DSL Tools no impiden. Puesto que no se nos ha impedido, hemos podido utilizar nombres de clase como "class", "base", utilizar tipos de datos no definidos,...

  • Problemas de las palabras reservadas "class" y "base":
El primer problema que hemos tenido que solventar ha sido el de compilacion producido por utilizar la palabra reservada "class" en nuestro DomainModel. Esta palabra reservada la hemos utilizado en la relacion entre "Esquema" y "Class". La solucion es tan sencilla como cambiarle el nombre a por ejemplo "classRole".

Identico problema hemos tenido entre las clases "Dimension" y "Base", cuyo rol se llamaba "base" y ha sido reemplazado por baseRole.

Una vez hecho esto , tendremos que sincronizar los cambios del DomainModel, con el Designer y aplicar mas tarde el botoncito de "Transform all templates" para que nos vuelva a generar las plantillas de código y veremos otros errores distintos al compilar la solucion.

  • Error de tipo de datos mal definido:
Ahora veremos que los errores de antes han desaparecido y nos aparecen otros errores. Nos centraremos primero en uno un tanto extraño en el cual podemos ver que la generacion de código ha producido una línea c# no válida. Simplemente hace falta saber dónde ha sido declarada esa propiedad en el DomainModel, para darse cuenta que el error viene dado por no haber declarado correctamente sus tipos.

La propiedad en cuestion que da error al compilar es la siguiente:

private Proyecto.Fincarrera.ObjectOrientedMultidimensionalModel.DomainModel.AssociationType typePropertyStorage = Proyecto.Fincarrera.ObjectOrientedMultidimensionalModel.DomainModel.AssociationType.0;

En ella podemos ver claramente como le intenta poner a la propiedad , como nombre el número "0", lo cual es sintacticamente incorrecto y nos avisa el compilador con un estupendo error. Para arreglarlo, nos vamos a la declaracion en el DomainModel y nos damos cuenta que el error es porque tiene como tipo de datos "AssociationType" y valor por defecto 0. Si sabemos que va a ser un desplegable, pues le ponemos como tipo de datos entero y valor por defecto 0 y arreglado.


Una vez corregido esto, volvemos a transformar todos los templates y a recompilar.

  • Problema del caracter no válido dentro de una enumeracion:

Debido a nuestro Modelo de dominio en concreto, donde uno de los conectores tiene por nombre Rolls-upTo, al generarse los ficheros de código a partir de nuestras plantillas, ha vuelto a surgirnos un error de sintaxis.

public enum AssociationType
{
Rolls-upTo=0,
Completeness=1,
}

Como vemos, ese signo "-" es sintacticamente incorrecto y va a hacer que el compilador nos diga que esperaba un ";". Pues bien ahora hay que ir a detectar donde se ha declarado y cambiarlo. Veremos pues que en este caso se ha generado a partir de uno de los miembros de la enumeracion "AssociationType" de la que antes hablábamos porque tenia otro error y que su solucion vuelve a ser tan simple como eliminar ese signo "-".



Una vez conseguido esto, ya compila nuestro DSL y podemos hechar un primer vistazo al modelo. Claro esta, tendremos que retocarlo mas adelante pero ya tenemos un primer paso conseguido.

miércoles, marzo 15, 2006

Sincronizar DomainModel.dsldm y Designer.dsldd

Cuando escribo estas lineas, estoy utilizando el Visual Studio 2005 SDK CTP Febrero 2006, que trae las DSLTools integradas dentro de el. En esta revision de las DSL Tools existe un gran problema para el desarrollador de lenguajes de dominio, la sincronizacion del Modelo de dominio y del Diseñador grafico.

El modelo de dominio lo definimos graficamente ayudados por la interfaz gráfica que nos proporciona Visual Studio 2005. En el, desarrollamos restricciones de cardinalidad, herencias entre clases, agregaciones, conectores,...para definir nuestro Modelo de Dominio. Esta definicion gráfica, se nos genera un fichero denominado DomainModel.dsldm dentro del proyecto DomainModel. Hasta aqui todo correcto, el problema viene luego a la hora de sincronizarnos con el diseñador gráfico, que es el que van a usar los "modeladores" o personas que usaran el Lenguaje de Dominio específico que hemos creado para ellos. En esta version de Febrero de las DSL Tools no se incluye ningun tipo de diseñador gráfico para el fichero Designer.dsldd por lo que te toca editar cientos de lineas XML formateado para especificar las dependencias, formas de figuras,...es decir un lio tremendo.

Para esta tarea, de forma no oficial, la empresa ModeliSoft ha creado un programa externo que se encarga de procesar el fichero DomainModel.dsldm y permitirnos en funcion de el, que sincronicemos nuestro diseñador gráfico. Es de muy agradecer esta herramienta porque como veremos, aunque no es facil utilizar las DSL Tools en esta etapa temprana, con esta herramienta, una de las mayores pegas con las que nos podemos encontrar ahora se disipan, la sincronizacion dsldm y dsldd.

Mi intencion en este post no es hacer un tutorial de uso de la herramienta , puesto que se encuentra en la misma web antes mencionada, sino exponer los problemas con los que nos estamos encontrando al utilizarla.

El primer problema que nos encontramos es que si hacemos el DomainModel.dsldm directamente y una vez hecho abrimos la aplicacion Dsldm2Dd.exe y cargamos el archivo Designer.dsldd de nuestro proyecto, vamos a ver un terrorifico error que nos va a hacer creer que no podemos utilizar la herramienta teniendo que programar a mano el XML. Nada mas lejos de la realidad puesto que veremos como con unos sencillos cambios arreglaremos esta situacion.

Si al abrir la herramienta Dsldm2Dd.exe y cargar la configuracion de nuestro Designer.dsldd nos da un error del JIT de .NET o que no es posible realizar la carga porque parece que el archivo que intenta cargar no es un archivo dsldd válido, es porque la clase raiz, es decir, la que le dice la superficie en la que pintar (el esquema propiamente dicho donde vamos a dibujar nuestro modelo) ha cambiado y no hay relacion ninguna entre el DomainModel.dsldm y el Designer.dsldd. Para saltarnos este error y poder comenzar a trabajar con la herramienta, lo que debemos hacer es abrir el fichero Designer.dsldd y reemplazar la cadena "ExampleModel" por la cadena que identifique la clase raiz de nuestro modelo; en nuestro caso "Esquema". Una vez hecho eso y guardado veremos como ahora si que nos funcionará la herramienta y ya podremos continuar usándola.

Por ejemplo, una ocurrencia que tendriamos que cambiar seria esta:
<>
<>
<>
<>
....DomainModel.ObjectOrientedMultidimensionalModel/ExampleModel
< /class>
< /childCollections>
...
Cambiaríamos "ExampleModel" por "Esquema".

Esto es debido a que cuando comenzamos la creacion de nuestro modelo de dominio, lo que hacemos es comenzar desde un "lenguaje mínimo", y este lenguaje mínimo si que viene ya sincronizado en las plantillas dsldm y dsldd pero cuando editamos el dsldm, el dsldd no se modifica y por eso tenemos que darle una ayudita a la herramienta de Modelisoft, para que empiece sabiendo por lo menos el punto de partida o nombre del esquema.


Aqui podemos ver los dos archivos mencionados: DomainModel.dsldm y Designer.dsldd

Crear funciones para el parser

Tambien llamados "ClassFeatures", con su sintaxis <#+ ClassFeature #>, nos permiten definirnos funciones para que se ejecuten en el parser antes de generar el código y podamos hacer cambios en el mismo.

Un tipico ejemplo es el de el nombre de una tabla de sql. Obviando características especiales de SQL Server como poner los nombres entre corchetes; si hacemos "create table Tabla 3", nos dara un error porque no sabe que el nombre de la tabla tiene un espacio. Pues bien, podemos hacer para que o bien nos genere los corchetes ( quedando "create table [Tabla 3]") o que nos quite el/los espacio/s en blanco (quedando "create Table Tabla3").

Optando por la segunda forma porque de paso veremos como utilizar la directiva import y el uso de clases externas, lo que habria que hacer es lo siguiente:

  • 1) Importar el namespace System.Text.RegularExpressions
Esto se hace añadiendo al principio del template la siguiente directiva:
<#@ import namespace = "System.Text.RegularExpressions" #>
  • 2) Definirnos en cualquier parte la ClassFeature siguiente:

<#+
private string FixWhiteSpaces(string typeName)
{
//Usa el namespace System.Text.RegularExpressions importado antes
string checkName = Regex.Replace(typeName," ","");
return(checkName.ToString());
}
#>

  • 3) Ahora solo falta usarlo, y se usa como cualquier funcion, pero desde dentro de un bloque de sentencias <#...#>. Por ejemplo, este código es válido.

<# foreach(Table table in this.Schema.tables) { //Como vemos, cojemos el nombre de la tabla del diagrama
string nombreTabla = table.Name;
// Si el nombre de la columna contiene espacios en blanco, se los quito
nombreTabla = FixWhiteSpaces(nombreTabla);
#>

Create Table <#=nombreTabla#>
(
)

<# //Cierro el bucle foreach } #>


Esto creara ficheros como el siguiente:


Create Table Tabla1
(
)
Create Table NiNombreTabla
(
)

Para ello, los nombres de las tablas podian haberse puesto en el diagrama como " Ni NombreTa b l a", puesto que con la funcion de antes , se eliminan los espacios en blanco.

Comentarios en los Templates

Para poner comentarios dentro de las plantillas de generacion de código, es tan simple como recordar que las Sentencias <#...#> son para delimitar código compilado en .net y por tanto si creamos una directiva en la cual lo unico que tenemos es un comentario, esta no se vera representada en el fichero generado.

Aqui tenemos un ejemplo de comentario.

<# // Soy un comentario y no voy a verme reflejado en el fichero de salida
#>

El problema viene porque al estar en un estado temprano, el parser de DSLTools tiene problemas con los comentarios y cree que hay Sentencias donde no las hay.

Por ejemplo:
<# /* Esto lo he comentado porque no consigo depurarlo
<#@ template debug="true" #>
<#@ import namespace="System.Diagnostics" #>
*/
#>
Aunque es sintacticamente correcto, nos da error el compilador porque el parser del template se lia con los #> y cree que hemos cerrado la Sentencia cuando realmente tendria que pasar de largo porque esta dentro de un comentario. Esto hace que lo que le de al compilador de .net sea un código no valido y por eso nos saca warnings y errores.

La solucion es obvia, para salir del paso le podemos decir que son caracteres especiales; al estar dentro de un comentario no hara nada.

<# /* Esto lo he comentado porque no consigo depurarlo
<\#@ template debug="true" \#>
<\#@ import namespace="System.Diagnostics" \#>
*/
#>

Caracteres especiales en generacion de codigo

Bueno a partir de ahora voy a hablar de Templates de generacion de código y para abreviar mas aun, de Templates. De esta forma vamos a ver que para que en nuestros templates de generacion de código se nos generen caracteres especiales como las comillas " o el signo menor que "<" (por ejemplo), hemos de hacer tal y como haciamos al programar en C/C++. Es decir con el caracter especial "\". De esta forma, podremos hacer lo siguiente: <# string texto = "\"Texto entre comillas"\" #>
<#= texto #>

Con lo que se nos generara: "Texto entre comillas" (con comillas incluidas)

martes, marzo 14, 2006

Problemas al depurar nuestro modelo

En la version DSL Tools CTP Febrero 2006 , hay veces que al intentar depurar nuestro modelo, nos da un error bastante feo y no podemos seguir trabajando, porque en ocasiones nisiquiera nos sale el toolbox de nuestro modelo en el VS activo.

El error es como el siguiente:
  • "Package Enrique.Catala.Designer.DSLmodel, Catala.DSLModel.Designer, Version=1.0.0.0, Culture=neutral, PublickeyToken='b03f5f7f11d50a3a' has failed to load properly ( GUID ={8F583BC9-4E70-4888-A667-4C461AC6D3A5})."

La forma de repararlo en un 90% es haciendo uso del enlace "Reset the Visual Studio 2005 Experimental hive" que nos aparece en "inicio->todos los programas->Visual Studio 2005 SDK->2006.2".
Por si no os sale, el comando es el siguiente:
  • "C:\Archivos de programa\Visual Studio 2005 SDK\2006.02\VisualStudioIntegration\Tools\Bin\VsRegEx.exe" GetOrig 8.0 Exp

Esto tarda un poquito y aunque no he mirado detenidamente lo que hace en realidad, elimina de la cache de ensamblados , las .dll de nuestro modelo, nos resetea el toolbox y borra nuestras preferencias y configuraciones (recordemos que del Visual Studio Experimental, no el normal que usamos para nuestros proyectos C# por ejemplo) y asi la proxima vez que entramos, ya tenemos la posibilidad de volver a compilar el modelo y trabajar normalmente.

Estre problema aunque no he encontrado informacion exacta de porqué se produce, si que me he dado cuenta que pasa por ejemplo cuando compilamos el modelo en una máquina y luego queremos hacer lo mismo en otra máquina distinta. Esto es lo que nos esta pasando a Vicente y a mi puesto que tenemos nuestro proyecto en un servidor SubVersioN y alguno de los ficheros que tenemos sincronizado no deberia estarlo porque se ve que guarda como un GID único que identifica a la máquina y hay que resetearlo.

Espero que te sirva. Por si acaso aqui tienes algunos links con problemas y soluciones de gente a la que le pasaba lo mismo:


Primeros pasos con la generacion de código

Voy a poner una breve introduccion de lo que mas nos puede servir para meternos de lleno con la generacion de código utilizando DSL Tools.

Primeramente, lo que tenemos que hacer es añadir un nuevo item en el proyecto: Proyect-> Add new Item -> Template -> Text File. Una vez tengamos la plantilla, lo renombramos como queramos, por ejemplo "sqlPlantilla.sql"

En la ventana de propiedades, hemos de poner en la celda de "Custom tool" la palabra: "TextTemplatingFileGenerator", para que el generador de plantillas, utilice esta plantilla para generar código. Podemos tener tantas plantillas como queramos.

TAGS PARA LAS PLANTILLAS
  • Directivas interesantes:
    • <#@ output extension=".sql" #>
Con esto nos aseguramos que la plantilla, va a generar un archivo nombrePlantilla.sql con el código generado.
Cabeceras e inclusion de copyright y demas:
Mediante la directiva include, podemos incluir en la generacion de código, una serie de informacion externa como copyright, encabezados, pies de pagina...
    • <#@ include file="c:\test.txt" #>
    • <#@ template debug="true" #>
      <#@ import namespace="System.Diagnostics" #>
Con estas dos directivas, se supone que podemos hacer depuracion en la generacion del código, justo mientras se encuentra el TextTemplatingFileGenerator en ejecucion, pero por desgracia no he podido probarlo porque me ha dado un error. Tengo que mirarlo mas en profundidad porque me interesa muchisimo.
Para poner breakpoints, basta con poner esto donde queramos pararnos:

<# Debugger.Break(); #>

  • Sentencias de Código:
Las sentencias de código tienen la siguiente sintaxis: <# SentenciaCodigo #>. Estas sentencias se tienen que escribir en el lenguaje que hayamos decidido utilizar para programarlas (por defecto C#) y han de compilarse correctamente, por lo que no podemos cometer errores de sintaxis, como es de suponer.

  • Bloques Expression

Los bloques Expression tienen la sintaxis <#= Expression #> y siren para añadir Strings al código generado en funcion de variables y/o propiedades calculadas.

Por ejemplo, esto seria un trozo de código con una sentencia de código que no se verá y un bloque Expression que si que se verá reflejado en el fichero de código que generemos.

<#
int result = 2*9
#>
<#= result #>

Lo que hara esto sera ejecutar el 2*9 mientras se encuentra el parser analizando, compilando y ejecutando nuestro template y escribir el valor de result al fichero de generacion de código. Es decir que en el fichero generado obtendriamos "18" solamente.