Etiqueta: cartolab

Trabajar con Word (docx) y Excel (xls y xlsx) desde Java

Iconos Word y Excel de MS OfficeEn Cartolab hemos trabajado ultimamente en procesar y generar documentos de Excel (xls y xlsx) y de Word (docx) desde Java. Tras probar algunas librerías open source las que estamos usando son:

Apache POI Spreadsheet para hojas de cálculo de Excel. Es fácil de usar y funciona bien tanto para los formatos binarios antiguos de xls (Excel 97-2007) como para xlsx (Excel 2007 OOXML). El How-To y la Quick Guide de la web son suficientes para empezar a escribir código.

Docx4j para documentos docx (OpenXML de Word 2007). La mejor forma de usarla es crear un documento vacio o con las cabeceras y pies de página desde Word o LibreOffice y definir en él los estilos. Desde nuestro código abrimos el documento y vamos añadiendo nuevos párrafos u otros elementos asignándole los estilos que hemos definido mediante el método addStyledParagraphOfText(styleID, text);. El styleID lo obtendremos consultado el fichero styles.xml que está comprimido dentro del docx. Si tenemos que hacer cosas más elaboradas el código se complica bastante pero al menos permite hacerlas. Para arrancar puedes leer como substituir placeholders por tu propio contenido, este otro artículo un poco más general y los ejemplos de código que vienen con la librería.

Para trabajar con documentos .doc de Word también probamos con Apache POI pero es complicado de usar y el resultado no es demasiado bueno. Así que por ahora no tenemos una alternativa válida para este formato.

En algún otro momento también hicimos pruebas con:

  • JasperReports que está muy bien para generar pdf pero el odt y el word lo saca maquetado en forma de tablas por lo que no nos valía.
  • iText. Que en versiones antiguas de la librería permitía sacar los resultados en rtf y era sencilla de emplear. Pero las últimas versiones se ha creado una nueva librería que no hemos probado todavía.

En esta pregunta de StackOverflow dan más alternativas. ¿Alguien usa otras librerías, preferiblemente open source y gratuitas, distintas a estas?

Organizar los ficheros de routes en nodejs – expressjs

Una de las tecnologías que estamos probando en Cartolab para aplicaciones web es nodejs con express como framework. Hay un montón de tutoriales de como empezar a usarlos, pero a poco que escribas empiezas a preguntarte como organizar el código, y ahí empiezan los problemas. express es un framework no opinativo, es decir proporciona un montón de utilidades pero da liberar total al usuario sobre como mezclarlas, así que se van desarrollando distintos modos de hacerlo.

La primera pregunta en mi casa sobre organizar el código fue acerca de los ficheros bajo el directorio routes. Podemos entender las routes de express como el equivalente al controlador en ese patrón llamado MVC que cada framework implementa como quiere, o viéndolo de otro modo como el mapeo entre una url y una función.

Vamos a ver cuatro estrategias distintas, cada una con sus ventajas e incovenientes.

Todo en app.js

La versión que se suele emplear en los tutoriales de iniciación. Escribimos en un único fichero todo el código de la aplicación.

  • Poco código boilerplate
  • Añadir una nueva url implica tocar un sólo fichero
  • Nada reusable
  • Sólo válido para proyectos pequeños

Es tan sencillo como escribir el mapeo antes de crear el servidor y usar funciones anónimas para la lógica


app.get('/', function(){res.send('root page'});

Mapear en app y la lógica en ficheros distintos

Este es el segundo ejemplo más habitual. Las url se definen en el fichero principal y las funcionalidades se agrupan en distintos ficheros bajo el directorio routes.

  • Añadir una nueva url implica tocar como mínimo dos ficheros
  • Favorece la reutilización, pero siempre debemos colocar las url a mano
  • Implica escribir más código que en el anterior y perder legibilidad

A pesar de que es muy habitual ver esto no me gusta porque no ganamos demasiado, y tener que hacer cambios en dos ficheros acaba introduciendo errores.


// app.js
var routes = require('./routes');  // Coje el fichero ./routes/index.js por defecto
var user = require('./routes/user');

app.get('/', routes.index);
app.get('/users', user.list);


// routes/user.js
exports.list = function(req, res){
res.send("respond with a resource");
};


// routes/index.js
exports.index = function(req, res){
res.send("root page");
};

Hacer el objeto app global y derivar todo hacia los ficheros de routes

Evitamos declarar app como variable local, para poder usarla en el resto de ficheros sin tener que preocuparnos de pasar parámetros. El código queda muy limpio pero se dificulta el testing y se pueden introducir bugs difíciles de detectar.

A mi me gusta esta aproximación cuando tenemos poco código y queremos hacer algo rápido, pero hay que ser consciente de los problemas que tiene.

  • No es una muy buena práctica hacer app global, en el siguiente punto vemos una mejora. Pero al hacerlo así obtenemos código más legible
  • Es bastante modular (excepto por hacer app global)
  • Es bastante legible
  • Hay separación de conceptos, cada fichero se encarga de unas determinadas url y funcionalidades

Referencias

Veamos como quedaría la implementación


// app.js
app = express(); //IMPORTANT! define the global app variable prior to requiring routes!
require('./routes');


// routes/index.js
require('./main');
require('./users');


// routes/main.js
app.get('/', function(req, res) {
res.send("root page");
});


// routes/users.js. list() could be an anonymous function, this is only for showing it in another way.

function list(req, res) {
res.send("user list");
};

app.get("/users", list);

Inyectar app en los ficheros de routes

Es similar al ejemplo anterior, pero el objeto principal es inyectado en los controladores en lugar de usarlo como una variable global. Sacrificamos un poco de legibilidad (hay que meter bastante código «inútil») pero a cambio ganamos en modularidad y testabilidad.

Veamos una posible implementación, teniendo en cuenta que este código no lo he visto en ningún sitio, lo he escrito a partir del artículo de dailyjs y podría tener algún otro problema.

A mi esta es la aproximación que más me gusta, cuando el código aumenta y no nos queremos ir a soluciones más complicadas.


// app.js
var app = express();
// ...
app.use(express.json());
require('./routes')(app); // Must be called after app.use(express.json()) and urlencoded;


// routes/index.js
module.exports = function(app) {
require('./main')(app);
require('./users')(app);
};


// routes/main.js
module.exports = function(app) {
function index(req, res) {
res.send("root page");
};
app.get('/', index);
};

Otras estrategias

Hay estrategias más complejas, que por ahora no me ha hecho falta probar.

Montar un firefox independiente para desarrollo web

Firefox_ScreenshotEn Cartolab llevamos ya una temporada investigando en uso de tecnologías web en el ámbito de la ingeniería cvil.

Una de las cosas que me incomodaron durante los primeros experimentos, era no tener un entorno de desarrollo específico. Al margen del IDE, en desarrollo web son fundamentales las herramientas que proporciona el navegador que usas para el testeo. En este caso, me molesta el mezclar plugins de desarrollo, con plugins normales que uso para la navegación. Tengo la sensación que se me descontrola el entorno de trabajo.

La solución es configurar un navegador específico para desarrollo. Lo cual, al menos en el caso de firefox, es más sencillo de lo que parece:

  1. Le echamos un ojo a las instrucciones de mozilla de como instalar firefox a mano. En resumen: descargar y descomprimir. Yo lo descargue en /usr/local/development
  2. Si ahora simplemente ejecutamos el fichero binario firefox veremos que no hemos ganado nada, aún tendremos nuestros marcadores, plugins, etc… Esto es porque firefox, guarda esta información en perfiles y usa por defecto el perfil indicado en el fichero $HOME/.mozilla/firefox/profiles.ini
  3. Debemos por tanto crear un nuevo perfil, pero antes haremos una copia de profiles.ini
  4. Creamos el perfil como recomiendan desde mozilla, ejecutando firefox -P. Yo cree el perfil dentro de la propia carpeta del firefox descargado a mano, para poder tener un sistema autocontenido.
  5. El paso anterior habrá modificado el fichero profiles.ini, añadiendo el nuevo. Pero lo que nosotros queremos es tener el modo desarrollo lo más aislado posible así que restauramos la copia que hicimos anteriormente
  6. Creamos un miniscript en nuestro PATH o donde queramos que ejecute nuestro firefox de desarrollo y le pase el parámetro -profile y el path al perfil de desarrollo que creamos. Yo cree un script ffdev en /usr/local/bin con el siguiente contenido

    #!/bin/sh
    cd /usr/local/development/firefox
    ./firefox -profile development-profile

Los menos puristas habrán observado, que en realidad, no es necesario complicarse tanto la vida bajando un firefox aparte. Llegaría con:

Crear un perfil nuevo en la carpeta por defecto, marcar el antiguo perfil como el que hay que usar por defecto y crear un script que arranque el nuevo perfil firefox -P "Nombre del Nuevo Perfil"

Si hemos optado por la primera altenativa y finalmente decidimos pasar a la segunda, un sólo firefox en el sistema que se actualice al ritmo que marca nuestra distribución, el cambio es tan sencillo, como copiar la carpeta de perfil de desarrollo a una nueva ubicación (el
directorio por defecto de perfiles sería lo lógico) y modificar el script para indicarle la nueva ruta del perfil y que firefox tiene que
usar. Si quisieramos poder abrirlo desde el Gestor de Perfiles o con la opción -P en lugar de -profile deberemos añadirlo a profiles.ini

¿Creéis que es útil configurar un perfil para desarrollo o no hace falta? ¿Cual de los dos métodos preferís?

Plugin de análisis de redes en gvSIG 1.x

Una pregunta habitual en las listas de correo de gvSIG es si hay alguna herramienta para realizar análisis de redes. En Cartolab hemos estado buscando enlaces a algunos recursos del plugin llamado «piloto de redes» que es el más empleado para estos análisis para poder compartirlos.

El plugin de piloto de redes (a veces también se lo llama «network extension«, «análisis de redes» o «extGraph«) es mantenido por Scolab y dispone de una página web en la forja de join-up, pero parece desactualizada.

 

Instalación

La última versión de este plugin es compatible con la versión 1.12 de gvSIG, y se puede instalar desde el administrador de complementos.

Herramientas -> Administrador de complementos -> Seleccionamos org.gvsig.graph y seguimos las instrucciones.

Resumen de uso

  1. Se carga una capa de líneas con los líneas conectadas, sin repetir y digitalizadas en el sentido de la circulación.
  2. Si queremos un análisis mas acertado deberíamos como mínimo un atributo donde esté definido el coste y otro en el que esté definido el sentido. El coste representa cuanto cuesta recorrer ese tramo en las unidades que nosotros queramos, distancia, tiempo,… En el campo sentido Asignamos un valor al sentido que se puede seguir por esa línea (el de la digitalización, ambos sentidos, contrario a la digitalización)
  3. A continuación vamos a Red->calcular topología de red que nos generará un fichero .net en el mismo direcotorio que la capa original con esa red. Aquí podemos decidir asignar cierta tolerancia a nuestra capa, por si los nodos no están perfectamente conectados,…
  4. En la siguiente pantalla, emparejamos los campos que nos solicitan. No es necesario rellenarlos todos. Si escogemos sentido le diremos que valor corresponde a de cada sentido posible.
  5. Cuando se carga la red nos preguntará por el campo que tiene un identificador para las geometrías, por ejemplo los nombres de las calles.
  6. Con la red cargada tenemos las opciones de introducir paradas, barreras o realizar los análisis. Las paradas se pueden administrar desde Red->Gestión de paradas. Son puntos de inicio, fin o de paso intermedio obligatorio de un cálculo de rutas. También se comportan como puntos a partir del cual determinar el equipamiento más cercano,… Las barreras son puntos por los que se impide el paso.
  7. Entre cálculo y cálculo recordar Red -> Borrar -> «Eliminar lo que nos interese»

Videotutoriales

  • Una serie de cuatro vídeos (unos 10, 15 minutos en total) con lo más básico del la extensión de redes para calcular rutas óptimas. Emplea la versión 1.1.2 de gvSIG pero permite ver lo más importante.
  • Vídeo de 6 minutos, demostrativo de varias de las funcionalidades de la extensión. . Cálculo de rutas. Matriz de distanticas y tiempos. Punto más cercano. Árbol de recubrimiento mínimo. Área de servicio. Está bien para de un vistazo saber todo lo que hace.

Manuales

Otros recursos

 

VII Jornadas de SIG Libre de Girona

Este año gracias a Cartolab he tenido la oportunidad de asistir de nuevo a las Jornadas de SIG Libre de Girona.

Como en años anteriores, el ambiente y la organización fueron magníficos. A pesar de que no había tanta gente como hace dos años, el compromiso de la comunidad geo con estas jornadas y el buen hacer del sigte hace que siempre merezca la pena ir.

Este año, desde cartolab, siguiendo la línea que tenemos para las jornadas de presentar contenidos formativos, análisis y cooperación para el desarrollo llevamos una comunicación sobre el Curso Online de SIG para Cooperación al Desarrollo , que ayudamos a elaborar el año pasado junto a Ingeniería Sin Fronteras, la empresa iCarto y el laboratorio de la USC, Laborate.

El eje de la presentación consistía en tratar de mostrar, como si bien las necesidades pueden ser iguales en los distintos territorios, las problemáticas que se daban en unos y en otros eran distintas. Por ejemplo la necesidad para la elaboración de un plan de ordenación territorial es igual en Galicia, que en Jinotega (Nicaragua), pero los problemas en Jinotega, donde sólo el 40% de las familias tiene una escritura de propiedad de la tierra, y sólo el 25% de las personas tiene algún tipo de ingreso , son distintos a los que nos encontraremos en Galicia. La presentación es algo minimalista pero si queréis más podéis anotaros al curso.

Integrando las correcciones de extCAD en OpenCADTools

He estado trabajando en integrar todas las correcciones que se hicieron en la extensión oficial de CAD para gvSIG, desde el nacimiento de  OpenCADTools en las propias opencadtools. Este artículo describe:

  • Como se realizó el proceso de integración para ver de donde pueden venir errores futuros y la extraña apariencia que tiene el repositorio actual.
  • Contar el método seguido en sí por si resulta útil a gente que tenga que hacer algo parecido.

Debo agradecer al Cartolab el que me haya cedido horas de mi trabajo diario para poder escribir este artículo y realizar la integración en si misma. Además, debo agradecer a los organizadores del codesprint de Münich por financiar mi estancia allí y a los participantes por las aportaciones recibidas.

El problema

Tenemos tres repositorios svn con código parecido pero no igual:

  • gvSIG. Contiene entre otras muchas cosas el proyecto extCAD. Se trata del código base con commits desde 2005 hasta la actualidad
  • gisEIEL. A partir del año 2006 la Universidade da Coruña, a través de un convenio con la Diputación de A Coruña, realizó un fork de las herramientas de CAD de la versión 0.x de gvSIG. Este desarrollo fue asignado al Laboratorio de Bases de Datos de dicha universidad. En su repositorio actual sólo está el resultado final del fork, no los commits intermedios, porque lo que no se pueden comparar los logs para hacer una integración de código más ordenada.
  • OpenCADTools. A partir de 2009, con financiación de la Diputación de Pontevedra y en el marco de los trabajos de desarollo de gvSIG-EIEL Cartolab hizo una integración del código de gisEIEL con el de gvSIG adaptando todo ello primero a la versión 1.1.2 de gvSIG y luego a la 1.9. Se dispone de todo el historial desde el principio hasta la actualidad. Posteriormente Cartolab continuo el desarrollo de las OpenCADTools como un proyecto propio.

Lo que queremos ahora es:

  1. Obtener las mejoras realizadas en los tres proyectos desde que evolucionaron por separado para obtener una extensión de CAD mucho más potente. Nos concentraremos en el código de gvSIG y el de OpenCADTools por ser los que más desarrollo han tenido y estar ambos adaptados a la rama 1.9 de gvSIG, mientras que gisEIEL continua en versiones más antiguas. Emplearemos el proyecto de gisEIEL sólo para consultar dudas de autoría o Copyright.
  2. Es fundamental respetar lo máximo posible la historia de commits. Debemos saber cuando se integró un cambio, por qué, y quien lo hizo. Esto nos permitirá prevenir errores futuros.
  3. Es fundamental respetar lo máximo posible la autoría y el copyright de todas las modificaciones.
  4. Nuestra meta final es además que el código resultante pueda ser integrado en el proyecto gvSIG, por tanto nuestra base debe ser el código de extCAD, y las mejoras de OpenCADTools deben poder ser introducidas en forma de parches sobre extCAD.

Para ello necesitamos poder comparar de forma sencilla estos tres repositorios. Dada la cantidad de commits que ha habido y la divergencia existente resulta muy complicado comparar los logs o encontrar un punto común. Haremos por tanto un análisis inicial clase a clase que nos permita ver el grueso de las diferencias y tomar decisiones.

Análisis clase a clase

  • Montamos un repositorio local de git que contenga en ramas separadas el código de cada proyecto.
  • Obtenemos un fichero de texto all_files.txt con todas los ficheros que hay (sin repetir) estén en una rama u otra. Haremos el listado de ficheros de cada rama mediante tree, y compararemos los ficheros con meld para incluír rapidamente los ficheros que están en una y no en otra en el fichero all_files.txt

    git checkout heads/extcad
    tree -fi --noreport > extcad_files.txt
    git checkout heads/opencadtools
    tree -fi --noreport > opencadtools_files.txt
    cp opencadtools_files.txt all_files.txt
  • Hacemos un script muy sencillo que mete un carácter = antes de cada línea de un fichero checked_files.txt para todos aquellos ficheros que no hayan variado.
  • Sobre el fichero checked_files.txt marcamos con una x aquellos ficheros que sabemos que no es necesario que comprobemos, por ejemplo el directorio install de OpenCADTools que con el nuevo sistema de paquetes de gvSIG está obsoleta. Algunos de estos ficheros serán eliminados a posteriori
  • Los ficheros distintos los revisaremos uno a uno con algo como esto:

    fileToCheck=./src/com/iver/cit/gvsig/CADExtension.java
    git diff master:$fileToCheck refs/heads/opencadtools:$fileToCheck

    La variable fileToCheck la rellenamos con un copy&paste desde checked_files.txt. Y vamos marcando en el fichero de checked_files.txt con una m aquellos en las que la «versión más correcta» sea la del trunk de gvSIG. A veces el cambio es simplemente una cabecera, indentado, …

Este proceso aunque algo tedioso nos permite hacernos una imagen mental del estado de los repositorios lo que aumentará nuestra capacidad para tomar decisiones.

Primera fase de la de integración

En el caso de OpenCADTools fue sencillo encontrar el punto en que se completo la migración de las herramientas desde la versión 1.1.2 de gvSIG a la 1.9. Perder el histórico de la migración no era grave y nos permitía simplificar el proceso, así que lo que se decidió fue escoger el commit en que esa migración se consideraba finalizaday volcar todo el repo de OpenCADTools en ese punto sobre el de extCAD.


# En un repo con sólo OpenCADTools, hacemos
$ git checkout -b ultimoMigracion
# 0f517d66 = commit de interés, del 14 de Septiembre con mensaje "Updated StartEditing from gvSIG 1.9"
$ git reset --hard 0f517d66
# y sobre nuestro repo de trabajo:
cp -r $repoOpenCadTools .

A continuación vamos descartando todos los ficheros en los que sepamos que el contenido del master es más válido, los marcados como m en la fase anterior:

git checkout -- los_ficheros_donde_prefiramos_el_master

Nuestros lectores más hábiles en el uso de git se habrán dado cuenta, de que podríamos hacer el análisis de los ficheros tipo m directamente en este paso, pero como ya comentamos, hacerlo del otro modo nos permite afianzar nuestro conocimiento de los repositorios.

Segunda fase de la integración

Ahora tendremos en nuestro repo ficheros nuevos y ficheros modificados.

Los ficheros nuevos son todos ellos nuevas herramientas cuyas clases pueden ser agrupadas. Así que vamos comiteándolos aprovechando para revisar las cabeceras y las autorías. Resulta sencillo identificar si una de estas nuevas clases fue desarrollada inicialmente por el Laboratorio de Bases de Datos y adaptada con posterioridad por Cartolab, o fue creada directamente por Cartolab. Basta comprobar si existe o no en el repositorio de gisEIEL. En general los autores concretos de cada clase o quienes la adaptaron están también idendificados en el código fuente, cuando esto no es así lo que se ha hecho ha sido poner de forma genérica «Laboratorio de Bases de Datos» y/o «Cartolab». La autoría se ha reflejado mediante anotaciones @author en el código fuente de las clases

De este modo vamos haciendo commits para las herramientas y dado que es git empleamos la opción –author para reflejar quien hizo el commit original en el repo de OpenCADTools (al menos de forma aproximada)

Los ficheros modificados en este caso son pocos, por lo que permite tomar decisiones de forma individual.

Tercera fase de la integración

Probablemete la fase más complicada. Nos toca integrar los 143 commits que hubo en OpenCADTools desde el que tomamos como referencia hasta el último commit previo a la integración.

Tras varias pruebas y sin encontrar una forma rápida y segura de integrar esos commits se optó por generar parches e ir integrándolos uno. En algunos casos hubo que retocar los parches o los ficheros a mano puesto que no se integraban correctamente.

Cuarta fase de la integración

Toca limar algunas aspectos, por ejemplo:

  • El nombre de los commiters, para lo que se emplea este script
  • Comprobar que podemos exportar lo que tenemos a un repositorio vacio de git (pasos 7 a 9)

Además se hace testeo funcional de las herramientas de CAD para encontrar posibles problemas en la integración y resolver los bugs que se deriven de ella.

Conclusiones

Dada la disparidad de la evolución de los repositorios el proceso fue tedioso. Pero ahora tenemos un repositorio git actualizado a los últimos cambios de las herramientas por defecto de gvSIG y de las opencadtools. Esto nos permite trazar el origen de algunos bugs, y realizar integración de parches en ambos sentidos, así que merece la pena.

Taller de gvSIG-EIEL en Valencia. Método 2

Como comentábamos en la anterior entrada hemos creado un fichero .iso que podéis «quemar» en un pendrive de al menos 4GB para seguir el taller de gvSIG-EIEL. Podéis descargar el .iso desde este enlace.

Tras quemarla podréis arrancar vuestro ordenador desde el PC configurando en la BIOS que arranque en primer lugar desde ahí. Se trata de una versión de ubuntu con gvSIG-EIEL y una base de datos PostGIS con datos de prueba, todo preinstalado.

Para quemar el pendrive podéis seguir estas instrucciones. para linux o para windows.

El usuario por defecto es «custom» sin clave. Para conectar a la base de datos usaremos:

  • servidor: localhost
  • usuario: user
  • clave: user
  • puerto: 5432
  • esquema: eiel_map_municipal
El fichero .iso también debería poder ser ejecutado desde una máquina virtual.
Si tenéis algún problema dejad un comentario o comentádnoslo antes del taller. Estaremos todos los días por las jornadas.

Taller de gvSIG-EIEL en Valencia. Método 1.

El jueves por la tarde en las Jornadas de gvSIG, Gonzalo y yo estaremos por parte de Cartolab impartiendo el taller sobre gvSIG-EIEL.

El taller está pensado para que los que acudan puedan seguir los ejemplos con su portátil. Dado que gvSIG-EIEL hace uso de una base de datos PostGIS para funcionar vamos a explicar dos formas distintas de poder seguir el taller.

La primera de ellas es que instaleis directamente en vuestro portátil la base de datos. Desde Ubuntu es tan sencillo como hacer:


sudo apt-get install postgresql-8.4-postgis pgadmin3

Y luego crear un template para postgis.

su postgres
createdb postgistemplate
createlang plpgsql postgistemplate
psql -d postgistemplate -f /usr/share/postgis/lwpostgis.sql
psql -d postgistemplate -f /usr/share/postgis/spatial_ref_sys.sql

Y en windows bajándose este pack y acordándose de seleccionar en el momento adecuado que también instale postgis.

Con motivo del taller vamos a proporcionar un nuevo set de datos que os podéis descargar desde este enlace. Aunque con los publicados en la página web es suficiente para hacer la mayoría de los ejemplos.

Desde la interfaz de pgAdmin3 se crea una nueva base de datos usando como template «template_postgis» y luego se emplea el set de datos que proporcionamos sobre la base de datos que acabamos de crear. En caso de que hayamos llamado gvsig-eiel a la base de datos hariamos:

psql -U postgres -p 5432 -h localhost -f gvsig-eiel.sql -d gvsig-eiel

En caso de duda este artículo puede ayudaros. Si tenéis alguna duda dejad un comentario en el blog o escribidme a fpuga ARROBA cartolab.es. Es importante que si vais a seguir el taller de forma activa traigais todo configurado.

gvSIG-EIEL podéis descargarlo de la propia página. Con motivo del taller hemos dispuesto un servidor alternativo por si hubiera problemas.

Mañana publicaré el segundo método. Vamos a distribuir un fichero que podreis volcar a un USB (mínimo 4GB y se perderán los datos que tuvierais en ellos) que actuará como sistema operativo completo con todo instalado que podéis ejecutar directamente desde el USB sin necesidad de tocar nada en el ordenador (aunque funciona considerablemente más lento)

gvSIG-EIEL 1.0 RC2 Published

Last week, Cartolab, the university lab where i work, released a new version of gvSIG-EIEL.

gvSIG-EIEL is a portable version of gvSIG bundled with some new extensions and some changes in the image designs. The application is focused to accomplish the requirements of the EIEL, an infrastructure inventory that some spanish public administration should do.

Some of this extensions like eye candy forms to introduce the data, or tools to verify that the data follow the established rules are specific for the eiel but others can be useful for any gvSIG’s user. As i think that the tools developed by Cartolab for gvSIG-EIEL (OpenCADTools, …) are already known i want to talk a bit of a new extension and the work done on Sextante.

The new extension is MapSheets developed by prodevelop in coordination with the gvSIG Association and ourselves to allow release it as a official gvSIG extension. MapSheets allows create map series in a really easy way. For those who comes from ESRI software it is something like MapBook but free and with some new features.

Under the umbrella of gvSIG-EIEL, Victor Olalla develops some new algorithms like the line properties that obtains some statistics for line shapefiles and can get the slope between two points of the line if a DEM is present. Also a useful improvement of the use of Sextante in gvSIG-EIEL is that it comes with two buttons to open the toolbox. The algorithms that appears in the second toolbox are easily configured editing the file alglist.txt that is in the sextante folder (es.unex.sextante) inside the gvSIG extensions folder. Just write in that file the names of the algorithms that you want to see in that file. If you only work with a subset of the algorithms this helps you to localize and use it.

MapSheet and the work on Sextante have been funded by the Spanish public administrations Deputación de Pontevedra and Dirección Xeral de Sostibilidade e Paisaxe de la Consellería de Medio Ambiente, Transporte e Infraestruturas de la Xunta de Galicia

Como carga gvSIG las extensiones

En la línea abierta por Andrés de «Como gvSIG hace xxx» os presento un artículo que explica como se gestiona la carga de las extensiones en gvSIG. Antes de nada debo agradecer a Cartolab cederme tiempo para poder escribirlo.

Lo que sucede cuando lanzamos gvSIG es que la máquina virtual de java ejecuta el método main() de la clase Launcher de andami, el framework que sostiene el sistema de ventanas y plugins de gvSIG.

A efectos de este artículo sobre la carga de extensiones podemos decir que ese método main() es el responsable de lo siguiente:

  1. Procesar los parámetros que se le pasan por línea de comandos
  2. Cargar los plugins
  3. Cargar las clases de los plugins
  4. Recuperar la configuración persistida de los plugins
  5. Inicializar las extensiones
  6. Cargar menus y toolbars
  7. Hacer la postinicialización de las extensiones

1.- Procesar los parámetros que se le pasan por línea de comandos

Lo más habitual es que la orden que ejecute el sistema operativo (quitando los parametros que se pasan a la jvm) sea algo parecido a:

$ java com.iver.andami.Launcher gvSIG gvSIG/extensiones «$@»

donde la parte en negrita serían los parámetros que pasamos al main(). En concreto ese segundo parámetro gvSIG/extensiones es el que está definiendo donde está la carpeta de plugins de gvSIG, como ruta relativa desde donde se encuentra el fichero andami.jar.

Es decir, que si bien el directorio de extensiones suele estar en un punto predefinido nosotros podriamos escoger otra ubicación.

2.- Carga de los plugins

Procesados los parámetros de entrada la aplicación recorre todos los directorios contenidos en la carpeta de plugins. Si dentro del directorio existe un fichero de nombre «config.xml» lo parsea y en caso de ser correcto añade el par [«nombre del directorio», objeto PluginConfig] al campo de la clase Launcher


private static HashMap pluginsConfig = new HashMap();

Donde PluginConfig es una clase que se encarga de mantener toda la información que aportan los ficheros config.xml.

Lo más interesante de esta fase es entender que el orden en que se recorren los directorios, y por tanto el orden en que luego se inicializarán las extensiones, es aleatorio, o en realidad es el orden que devuelve el método lisFiles() de la clase File de Java, que especifica en su documentación que el orden en se devuelven los ficheros no está asegurado y supongo, dependerá de la implementación concreta de la máquina virtual y del sistema operativo que se emplee.

Hay que aclarar que en este contexto, un plugin, es igual a un directorio contenido dentro del directorio de extensiones/plugins definido como parámetro.

3.- Carga de las clases de los plugins

Lo siguiente que intenta hacer es indexar todas las clases de todos los plugins. Para ello recorre pluginsConfig, solicitando el valor de la etiqueta del config <libraries library-dir=»VALOR» />. Lo más habitual es que ese VALOR sea «./», es decir el propio directorio del plugin. Para cada plugin mantiene un objeto PluginClassLoader que basicamente contiene un índice de todos ficheros .class que están dentro de los ficheros .zip o .jar que están en ese library-dir.

Para cada plugin se crea un objeto PluginServices que a su vez mantiene la instancia del PluginClassLoader que le corresponde. Esos PluginServices se almacenan en el campo

private static HashMap pluginsServices= new HashMap();

de la clase Launcher.

Hay que tener en cuenta que a la hora de cargar las clases de un plugin, si en el config se ha definido que depende de otro mediante una etiquetacarga la clases de la dependencia (de forma recursiva) antes que el nuestro. Por tanto, en pluginsServices los plugins se reordenan respecto a pluginsConfig poniendo los plugins de los que se depende antes. Se mantiene también una variable pluginsOrdered con el nombre de los plugins en el mismo orden que pluginsServices

4.- Persistencia de los plugins

Se actualiza el andamiConfig que contiene una lista (el fichero andami-config.xml habitualmente) que persiste con todos los plugins presentes el directorio de plugins.

Luego se recupera de disco la configuración persistida de los plugins en el fichero plugins-persistance.xml, y se setea esa configuración en el PluginServices asociado a cada plugin.

5.- Inicialización de las Extensiones

Es en esta fase cuando salen por consola los mensajes de:

Initializing extensions from «Nombre_del_plugin» (para cada plugin)

y

Initializing «Nombre_de_la_Extension» … (para cada extensión)

Se recorre pluginsOrdered, y para cada plugin se crea una instancia de cada extensión (en el orden que se define en el config del plugin) y se llama a su método initialize(). Además se almacena esas instancia en el campo de Launcher:

private static ArrayList extensions=new ArrayList();

Por el medio crea también un objeto ExtensionDecorator que nos da un control adicional sobre las extensiones pero esto no nos interesa a los efectos de este artículo.

6.- Menus y Toolbars

Se cargarn los menus y los toolbars definidos por los plugins a través de los métodos installPluginsMenus() y installPluginsControls().

7.- Post-inicialización de las extensiones

Se va llamando al método postInitialize de cada extensión en el orden en que aparecen en el array extensions. Con este paso finalizaría el proceso de carga.

Una cosa que no he investigado a fondo pero que intuyo que es así, es que en algún momento de este proceso se asocian las instancias del array extensions a los menús y botones del toolbar. De este modo las extensiones (clases que heredan de extension y aparecen en los config) se comportan como una especie de singleton, porque gvSIG siempre la recupera de ese array de extensiones, y cuando el desarrollador externo llama a PluginServices.getExtension(Class) la está recuperando de ahí también (del ExtensionDecorator del que hablamos antes en realidad, pero la idea es la misma)

Esto explica también porque cuando recompilamos nuestro código, si cambiamos algo en la clase de la extensión debemos cerrar y abrir gvSIG. La instancia de la extensión se crea durante la carga de gvSIG y se mantiene hasta que cerramos gvSIG, y por tanto no es «recargada» de los nuevos .class

Me quedan un par de dudas que quedan para estudiar para próximos posts o para quien se anime a escribir más artículos de la serie de «Como hace gvSIG XXX»:

  • Al parecer existe una extension del tipo ExclusiveUIExtension a la que se hace referencia en Launcher.initializeExclusiveUIExtension() que no tengo muy claro como funciona
  • Estaría bien explicar en detalle el comportamiento de los ExtensionDecorator
  • Estaría bien explicar detalladamente el proceso de creación y ubicación de los menús y toolbars
  • Algunas partes del código son un poco liosas. Tengo algunas ideas de como refactorizarlo así que si alguien se anima que pregunte