Wizards de Autogeneración
De MorfeoWiki
Tabla de contenidos |
Wizards de Autogeneración
- Autor: Javier de la Rosa, jrosa@yaco.es, Yaco Sistemas.
- Estado: Borrador inicial.
- Comentario: Documento en estado inicial con una visión subjetiva por parte de un desarrollador usuario de la plataforma que trabaja en entornos Linux. El código que contiene este documento no está testado ni ampliamente probado, por lo que el autor no se hace responsable de los efectos de uso que conlleve, pidiendo además colaboración en la corrección de los fallos que puedan derivarse. Además, hacer constar de que se trata de un esbozo, por lo que en ocasiones se percibirá cierta falta de cohesión entre las partes que forman el sistema que se describe en el presente.
Introducción
La plataforma MyMobileWeb permite la creación de aplicaciones web multidispositivos, utilizando para la lógica un lenguaje declarativo de definición de interfaces en conjunción con una extensión de hojas de estilo en cascada CSS. Toda la programación se realiza en Java a través de las llamadas operaciones de aplicación (OA), que sirven de enlace entre los datos de la aplicación y las presentaciones (data binding). La potencia y versatilidad de MyMobileWeb es indiscutible, sin embargo, la curva de aprendizaje requerida puede ser excesiva para el desarrollo de pequeñas aplicaciones con un enfoque muy determinado, esto es, aplicaciones de presencia en Internet para empresas, catálogos on-line, etc. Por este motivo, el presente documento propone una alternativa que permita automatizar la creación de este tipo de aplicaciones, restringiendo las vastas posibilidades de la plataforma en un subconjunto de los componentes en base a ficheros XML de fácil configuración y más generales. Estos serán generados por un wizard y, posteriormente, pasados como parámetros a un generador que se encargará de manipularlos y adecuarlos según una serie de plantillas para producir la aplicación final (.war) con las herramientas de generación (DeployTools) de MyMobileWeb. La herramienta, aun en desarrollo, será denominada en esta documento como Gemplate.
El documento se divide en X partes: en la primera podemos encontrar una descripción más completa del flujo que sigue la información hasta que la aplicación es generada. Las siguientes secciones tratan cada una de las partes en que se divide el workflow y que puede trabajar independientemente de las demás.
Flujo
En la siguiente figura se muestra un diagrama del flujo de la información y los distintos estados o fases por los que pasa el generador de aplicaciones basado en plantillas (en adelante, Gemplate).
Pasemos a comentar un poco la ilustración.
- El usuario final se enfrentará a un panel wizard con en el que podrá consultar la lista de plantillas disponibles en el respositorio, mostrando un compositor para facilitar el rellenado de datos que la plantilla escogida requiera.
- El mismo wizard deberá comprobar la validez de los datos para evitar generar un XML erróneo, e informará de tales circunstancias (como literales demasiado largos, traducciones omitidas, etc.).
- El fichero XML generado tendrá una estructura formal (de la que más abajo se muestra una proposición) y entre sus datos constará con la plantilla escogida.
- Con la información del XML (que contiene los datos introducidos por el usuario) y con la plantilla obtenida del repositorio, la herramienta Gemplate generará un proyecto Eclipse Tomcat funcional que puede ser perfectamente editado.
- En algunos casos, la plantilla puede requerir de una administración web separada de la interfaz de la aplicación (gestión de catálogo). Para conseguir esto, se propone que Gemplate genere una aplicación con acceso a base de datos para su gestión. Idealmente, esta base de datos debería contener toda la información del XML salida del wizard, para así poder tener un control absoluto sobre las modificaciones.
- Gemplate también se encargará de llamar a las herramientas de generación MyMobileWeb, para lo cual habrá que configurar Gemplate con las rutas en las que se encuentren las DeployTools.
- Cuando MyMobileWeb termine su trabajo, Gemplate empaquetará la aplicación en un fichero desplegable .war eliminando la información redundante e innecesaria como el ćodigo de las OPs o los ficheros .java.
- Con la aplicación en formato .war el despliegue es automático en servidores Apache Tomcat. Otro asunto a resolver sería la aplicación de gestión de la base de datos si procede.
Plantillas
En primera instancia, una plantilla no es más que una aplicación MyMobileWeb Eclipse Tomcat bien definida para un tipo de aplicación muy concreto. De esta manera cuenta con toda la estructura de directorios (OP's, presentaciones, OA's, hojas de estilo, etc.), con la salvedad de que la información que sería distinta entre diferentes implementaciones de una misma aplicación sencillamente no existe en la plantilla. Supongamos una aplicación que muestre una página inicial para "MiNegocio", un "Quiénes somos" e información sobre "Qué hacemos"; con esto, la estructura de directorios de la posible plantilla promotion podría ser la siguiente:
promotion |-- OPs | |-- Includes | | `-- generic | | |-- foot.xml | | `-- head.xml | |-- Messages | | `-- generic | | |-- error.xml | | |-- information.xml | | |-- plain.xml | | |-- question.xml | | `-- warning.xml | |-- Start | | `-- generic | | `-- main.xml | |-- What | | `-- generic | | `-- main.xml | `-- Who | `-- generic | `-- main.xml |-- WEB-INF | |-- src | | `-- mobi | | `-- promotion | | |-- MyAppInitializer.java | | |-- MyConstants.java | | |-- MyContextVariables.java | | |-- MyOAs.java | | |-- MyOPs.java | | |-- MyPresentations.java | | |-- handlers | | | |-- DefaultEventHandler.java | | | |-- start | | | | |-- StartEventHandler.java | | | | `-- MainEventHandler.java | | | |-- what | | | | |-- WhatEventHandler.java | | | | `-- MainEventHandler.java | | | |-- who | | | | |-- WhoEventHandler.java | | | | `-- MainEventHandler.java | | | `-- start | | | | |-- StartEventHandler.java | | | | `-- MainEventHandler.java | | |-- login | | | `-- MyCustomLogin.class | | `-- oas | | |-- ... | |-- lib | | |-- ... | `-- web.xml |-- config | |-- MyApplication.xml | |-- MyMobileWeb.DevMng.xml | |-- MyMobileWeb.Global.xml | |-- MyMobileWeb.ImageTranscoder.xml | |-- MyMobileWeb.PropMng.xml | |-- OAConfig.xml | `-- logs | |-- log4j.dtd | `-- traces.xml |-- css | |-- ... | |-- i18N | |-- ... | |-- index.jsp |-- template.php `-- wizard.xml
Se aprecia que no es más que una simple estructura, igual a la de cualquier otra aplicación completa pero que cuenta con una particularidad: la inclusión de dos ficheros nuevos
- template.php. La elección del lenguaje PHP no responde a ninguna preferencia en especial, únicamente es el usado para las pruebas y para el código de Gemplate, pero puede cambiarse sin problemas en posteriores versiones ya que la idea es lo importante.
- Tal y como está ideado actualmente, template.php debe tener una función principal denominada template() que recibe como parámetro una variable en SimpleXML con el árbol del fichero .xml generado por el wizard. Con esa información debe ser capaz de realizar los cambios necesarios para adapatar la plantilla con la información real proveída por el usuario. El procedimiento de generación, que de seguro requerirá iterar por el árbol del fichero XML, dependerá del programador que desarrolle la plantilla:
- Usando variables de aplicación de MyApplication.xml. Este caso es el más sencillo, ya que la función de la plantilla template() será extremadamente simple de programar; no obstante, habría que resolver el problema que se plantearía con los idiomas.
- Modificando mediante reemplazo de texto. Este método consistiría en colocar marcas en los ficheros que sea necesario modificar y realizar reemplazos de texto entre en las marcas escribiendo el contenido apropiado según el XML de parámetros.
- Escribiendo de nuevo los ficheros. El procedimiento goza con la particularidad de controlar por completo la escritura en los ficheros, pero necesitaría de librerías de apoyo para reutilizar al máximo y ahorrar en código.
- También es posible una combinación de los anteriores o incluso algún otro método.
- wizard.xml. Este fichero contendrá simplemente una estructura de datos que permitirá saber al wizard qué parámetros debe mostrar para modificar, con qué tipo de dato y en qué fichero.
La plantilla puede, o más bien debe, ser empaquetada y comprimida para que ocupe lo mínimo posible.
Wizard
Versión 0.0.1
Una primera versión del wizard debería, al menos, cumplir los siguientes puntos:
- Leer el directorio del repositorio y presentar todas las opciones disponibles categorizadas.
- Una vez seleccionada la plantilla, leer el fichero wizard.xml para poder renderizar correctamente los controles que permitirán la modificación de los parámetros pertinentes de ser introducidos por el usuario.
- Crear un índice con los elementos modificables para poder acceder a cada uno en cualquier momento.
- Poder volver a editar cada apartado cuantas veces se necesite.
- Mostrar previsualizaciones de cada presentación con los datos que el usuario vaya añadiendo.
- Mostrar campos para los distintos idiomas.
- Validar cada campo con la longitud permitida para las cadenas, codificación, etc. avisando al usuario de la incorrección de datos y evitando que pueda introducirlos mal.
- Finalizar de forma irreversible la toma de datos.
Cuando el proceso termine, se generará un fichero template.xml con toda la información obtenida
Versión 0.0.2
Yendo un poco más allá, sobrepasando la explicación dada y por supuesto eludiendo las complicaciones que conlleve, una wizard ideal no sólo se restringiría al rellenado de los datos que la plantilla demande, sino a un completo editor visual de componentes de las plantillas, eliminando el concepto de plantilla en sí y creando un repositorio de componentes (que bien podrían ser a nivel de OPs o de Presentación). De esta manera podría tenerse una API de acceso a algo que podríamos llamar MyMobileWeb.Components que utilizase ReST para la comunicación descentralizando así la aplicación mashup de edición visual Drag&Drop (nuestro antiguo wizard) del repositorio donde residirían los componentes. Este enfoque, basten distinto al propuesto inicialmente, permitiría que terceros creasen widgets MyMobileWeb.Components y los integrasen en sus webs multidispositivos previa sindicación al nuevo wizard.
Lenguaje de definición de parámetros XML
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!--
Cada proyecto tendrá que esta dentro de un tag <mobi> en el que
se deberá especificar el nombre y la ruta donde será generado.
-->
<mobi name="miempresa.mobi" path="/var/lib/tomcat5.5/webapps">
<!-- Indica la plantilla usada para generar el proyecto MyMobileWeb. -->
<template>/opt/Gemplate/promotion</template>
<!--
Mediante <lang> indicamos el lenguaje por defecto así como
los lenguajes soportados por la aplicación.
-->
<lang>
<!-- Indica el lenguaje por defecto. -->
<default>es_ES</default>
<!-- Lista separada por comas de los lenguajes soportados -->
<support>eng_US</support>
</lang>
<!-- Esta imagen se usará como cabecera donde sea posible. -->
<image>/tmp/logo.jpg</image>
<!--
Por defecto las etiquetas obedecerán al lenguaje por defecto.
El tag <title> (único) indica el título de la pantalla y, en este caso,
de la pantalla inicial.
-->
<title>Mi Empresa</title>
<title lang="eng_US">My Company</title>
<!--
Habrá tantos tags <text> como se deseen, pudiéndose traducir indicando
para ello el id del tag al que traducen. Por supuesto, las etiquetas de
un lenguaje no se mostrarán en las de otro.
-->
<text id="slogan">Líderes en soluciones tal y tal</text>
<text id="slogan" lang="eng_US">Leaders about blah blah solutions</text>
<!--
Tras la pantalla de presentación que se define en el raíz con los elementos
anteriores, tenemos el menú principal, que tomará los elementos <op> (Operaciones
de Presentación) y los mostrará según las propiedades indicadas.
-->
<op id="Who">
<title>Quiénes somos</title>
<text>Somos los que tenemos que ser</text>
<!-- Renderizan a enlaces hacia otras <op>. -->
<link to="trabajos" id="info">Más Info</link>
<link to="trabajos" id="info" lang="eng_US">More Info</link>
<!--
Creará un enlace hacia una pantalla definida con los
atributos que se le indiquen.
-->
<screen id="otras">
<title>Otra información</title>
<text>Pues otra información</text>
</screen>
</op>
<op id="Work">
<title>Líneas de negocio</title>
<text>Nos dedicamos a cosas de la vidar</text>
<!-- Renderizan a enlaces hacia otras <op>. -->
<link to="Who/Others" id="info">Más Info</link>
<!-- Incluye una pantalla de otra opción. -->
<include value="Who/Others"/>
</op>
<!--
Consideraciones
1) La idea es hacer la aplicación para un único idioma y después que
exista una pre-generación opcional que incluya las tags repetidas para
cada idioma y facilitar así la traducción.
2) Se trata de una primera aproximación para un caso muy básico sin
funcionalidad ni consultas a base de datos, pero puede ser un comienzo.
3) Estaría genial crear una DTD para validación por cada plantilla o
uno global.
4) En última instancia, este fichero, único por site .mobi, deberá ser
generado por una aplicación gráfica que facilita el rellenado y el
cumplimiento de la DTD.
5) Por defecto se incluirán elementos de navegación 'Atrás' e 'Inicio'.
-->
</mobi>
Generador Gemplate
Gemplate es el engranaje que hace todo funcione, la piedra angular sobre la que se apoya la ejecución de todo el sistema. Inicialmente escrito en PHP-cli, necesita de un fichero de configuración config.php en el que se especifican las variables necesarias para el correcto funcionamiento. Vemos abajo un ejemplo de como podría ser config.php.
<? //////////////// // config.php // //////////////// $JAVA_HOME = "/usr/lib/jvm/java-1.5.0-sun/"; $MYMOBILEWEB_JSPGEN_HOME = "/opt/DeployTools/bin/generator.sh"; $MYMOBILEWEB_LITEXT_HOME = "/opt/DeployTools/bin/litextractor.sh"; $MYMOBILEWEB_DEPLOYTOOLS = "/opt/DeployTools/"; $PATH_TO_DEPLOY = "/var/lib/tomcat5.5/webapps/" // If $DEBUG_TMPL is true, JSP's, Eclipse project either Tomcat project won't be generated $DEBUG_GMPL = false; ?>
Para comenzar, necesita un único parámetro que indica la ubicación del fichero generado por el wizard y que, en el formato de definición de parámetros XML explicado arriba, va integrada toda la información que el usuario ha introducido a través del wizard, incluyendo la plantilla seleccionada.
<?
// Obtenemos el valor el fichero XML de la entrada estándar
if (empty($argv[1])) {
print "Error: Param missing.\n";
print "Use: gemplate template.xml\n";
exit(1);
}
// Especificamos la ruta del fichero
$file = $argv[1];
// Comprobamos que el fichero exista
if (!file_exists($file)) {
print "Error: The file \"$file\" doesn't exist.\n";
exit(1);
}
// Incluimos el fichero de configuración
include("config.php");
// Verificamos que las rutas existan
$ENV_VARS = array($JAVA_HOME, $MYMOBILEWEB_JSPGEN_HOME, $MYMOBILEWEB_LITEXT_HOME, $MYMOBILEWEB_DEPLOYTOOLS, $PATH_TO_DEPLOY);
foreach($ENV_VARS as $var) {
if (!file_exists($var)) {
print "Error: The path \"$var\" doesn't exist or isn't correct.\nPlease, check your config.php settings.\n";
exit(1);
}
}
// Cargamos el objeto XML en la variable $xml
$mobi = simplexml_load_file($file);
// Creamos el directorio del proyecto
if ($mobi['path']=='.') $mobi['path'] = realpath($mobi['path']);
if (!file_exists($mobi['path'])) {
print "Error: The path \"$mobi[path]\" doesn't exist or isn't correct.\nPlease, check your path param in $file.\n";
exit(1);
}
$project = $mobi['path']."/".$mobi['name'];
if (!file_exists($project))
mkdir ($project);
// Identificamos la plantilla y la copiamos
if (!file_exists($mobi->template) || !file_exists($mobi->template."/template.php") || empty($mobi->template)) {
if (!file_exists($mobi->template.".zip")) {
print "Error: The template \"$mobi->template\" doesn't exist or isn't correct.\n";
exit(1);
} else {
print "Extracting template '$mobi->template'... ";
exec("unzip ".($mobi->template).".zip");
print "OK.\n";
}
}
print "Copying template '$mobi->template'...\n";
exec("cp -r ".($mobi->template)." ".$project.");
print "OK\n";
// Cargamos la clase de presentaciones
include("presentation.class.php");
// Cargamos la plantilla y la ejecutamos
include($mobi->template."/template.php");
print "Running template '$mobi->template':\n";
template($mobi);
// Eliminamos el archivo principal de la plantilla y del wizard
exec("rm -r ".$mobi['path']."/".$mobi['name']."/template.php");
exec("rm -r ".$mobi['path']."/".$mobi['name']."/wizard.xml");
// Comprobamos el modo de ejecución
if ($DEBUG_GMPL) {
print "Gemplate Debug mode: OK\n";
} else {
// Generamos usando las DeployTools
print "Generating MyMobileWeb Eclipse project...\n";
system("sh ".$MYMOBILEWEB_JSPGEN_HOME." /".$mobi['name']." ".$mobi['path']."/".$mobi['name']);
// Creamos un fichero .war para Tomcat basándonos en ocawar.sh [1]
print "Generating Tomcat .war file... ";
exec(ocawar.sh ".$mobi['name']." ".$mobi['path']."/".$mobi['name']." $PATH_TO_DEPLOY);
print "OK\n";
// Eliminamos el proyecto Eclipse temporal
print "Removing MyMobileWeb Eclipse project... ";
exec("rm -rf ".$mobi['path']."/".$mobi['name']);
print "OK\n";
}
// Eliminamos la plantilla extraída del .zip si es necesario
if (file_exists($mobi->template.".zip")) {
if (file_exists($mobi->template)) {
print "Removing temporal template '$mobi->template'...";
exec("rm -rf ".$mobi->template);
print "OK\n";
}
}
?>

