Etiqueta: gvsig

Usando GeoProcesos en gvSIG desde Java

La semana pasada había un correo en la lista de desarrollo de gvSIG preguntando como poder lanzar geoprocesos desde tu propio plugin mediante Java. Tras una pequeña investigación he escrito un código de ejemplo que espero que sea útil a quien tenga esta necesidad.

Descargar el código

A mi particularme me gusta descargar el código fuente de las partes de gvSIG con las que voy a trabajar. Esto simplifica el usar las herramientas del IDE para saber como usarlo, encontrar errores, y revisar los tests, en caso de haberlos, para tener pistas de como escribir mi propio código.

Para ello primero se mira la versión del plugin que se corresponda con la versión de gvSIG que estás usando. Creo que lo más fácil es descargar una versión portable de gvSIG. Entrar a la carpeta que contiene el plugin, en este caso org.gvsig.geoprocess.app.mainplugin y abrir el fichero package.info. En la property version está el tag del repo correspondiente a esa versión. Por ejemplo para la 2.3RC2 sería el 2.266. Por tanto para descargar el repo haremos:


svn checkout http://devel.gvsig.org/svn/gvsig-geoprocess/org.gvsig.geoprocess/tags/org.gvsig.geoprocess-2.2.66/

A continuación,e n caso de usar Eclipse, iremos a import -> Existing maven projects, e importaremos la raíz del nuevo plugin descargado.

Añadir las dependencias

Al desarrollar en gvSIG debemos tener en cuenta que las dependencias de nuestro plugin, por decirlo de algún modo, serán de dos tipos. En «Tiempo de desarrollo», y en «Tiempo de ejecución». Las dependencias en desarrollo se definen en el pom del proyecto permitiéndonos definir el classpath de desarrollo para trabajar con las clases que nos hagan falta.

En ejecución, cuando estamos probando o ejecutando gvSIG, el classpath se define de manera dinámica por decirlo de algún modo en el fichero de config.xml. gvSIG buscará entre las dependencias que hayamos definido en el config las clases que se pueden usar en nuestro plugin.

Para que quede claro, a nuestro pom se añadirán otros proyectos maven. A nuestro config se añadirán plugins de gvSIG.

Por ejemplo para el caso de usar los geoprocesos, añadiremos al pom:



org.gvsig
org.gvsig.geoprocess.lib.api
2.2.66


org.gvsig
org.gvsig.geoprocess.lib.sextante
2.2.66

y al config



Obtener el algoritmo que queremos

Esta una de las partes en las que tengo más dudas que esté correcta.

En general accederemos a las funcionalidades de gvSIG a través de un Locator que nos dará un Manager que nos dará la funcionalidad. En el caso de los geoprocesos sería:


String ALG_NAME = "gvSIG-intersection";
SextanteGeoProcessManager manager = (SextanteGeoProcessManager) GeoProcessLocator.getGeoProcessManager();
HashMap algs = manager.getAlgorithms();
GeoAlgorithm alg = algs.get(ALG_NAME);

Debemos castear a la implementación por defecto del manager SextanteGeoProcessManager porque la interfaz en sí no proporciona el método getAlgorithms. Esto diría que es un bug.

La forma de obtener ALG_NAME, no estoy seguro de cual es. En principio lo más fácil sería poner un breakpoint y mirar los valores de algs. Aunque en mi caso sólo salen los propios de gvSIG y no los de Sextante.

Seteando valores al algoritmo

Todos los algoritmos definen un método defineCharacteristics que nos indican los valores que recibe, tanto de entrada como de salida. Esta definición de valores se obtiene a través del método getParameters

En nuestro código debemos obtener cada uno de los parámetros necesarios y setear su valor real para nuestro caso. Por ejemplo:


private void setParams(GeoAlgorithm alg) throws WrongParameterIDException {
ParametersSet params = alg.getParameters();

FLyrVect interLyr = getLayer("inter");
FlyrVectIVectorLayer inter = new FlyrVectIVectorLayer();
inter.create(interLyr);

FLyrVect layerLyr = getLayer("layer");
FlyrVectIVectorLayer layer = new FlyrVectIVectorLayer();
layer.create(layerLyr);

params.getParameter(IntersectionAlgorithm.INTER).setParameterValue(
inter);
params.getParameter(IntersectionAlgorithm.LAYER).setParameterValue(
layer);
params.getParameter(IntersectionAlgorithm.SELECTGEOM_INPUT)
.setParameterValue(false);
params.getParameter(IntersectionAlgorithm.SELECTGEOM_OVERLAY)
.setParameterValue(false);
}

En este caso para no escribir a mano los idenfificadores de los parámetros uso las variables estáticas definidas en el propio algoritmo. Eso hace que haya que añadir al pom el algortimo:



org.gvsig
org.gvsig.geoprocess.algorithm.intersection
2.2.66

Para las capas de entrada al algoritmo hay que generar una FlyrVectIVectorLayer. Como se muestra en el código de ejemplo lo más sencillo es obtener un FLyrVect y construirla con el create.

Ejecutando el algoritmo

Los algoritmos se lanzan mediante el método execute que como indica la documentación admite hasta tres parámetros.

  • ITaskMonitor task. Que puede ser nulo y permite monitorizar el estado para por ejemplo poner una barra de progreso al usuario
  • HashMap outputMap. Que permite modificar los nombres que sextante asigna a los parámetros de salida (en general capas)
  • OutputFactory outputFactory. Define como se crearán los objetos de salida. Puede ser nuestra propia implementación o usar la factoría por defecto

Por tanto ejecutarlo sería simplemente:


alg.execute(null, new DefaultOutputFactory(), null);

Obteniendo los resultados

Con la factoría por defecto las capas se crean en un directorio temporal que en linux es /tmp/tmp-andami y les asigna nombres aleatorios (creo que basados en el timestamp). Supongo que habrá alguna utilidad que nos permite ejecutar una especie de FinalActions para añdirlos automáticamente a la vista. O implementando nuestra propia OutputFactory podríamos definir otras rutas. También diría que podemos prescindir del OutputFactory y lanzar el algoritmo mediante processAlgorithm si igual que hicimos con los parámetros de entrada seteamos adecuadamente los valores de salida, especialmente el OutputChannel de las capas.

En todo caso el método getOutputObjects nos devuelve los objetos de salida, así por ejemplo podríamos llegar el FlyrVectIVectorLayer de la capa de polígonos de salida con:


OutputObjectsSet outputSet = alg.getOutputObjects();
OutPut output = outputSet.getOutPut(IntersectionAlgorithm.RESULT_POL)
FlyrVectIVectorLayer result_pol = (FlyrVectIVectorLayer) output.getOutputObject();

Compilando y depurando un plugin de ejemplo para gvSIG 2.1 desde Eclipse

Joaquín del Cerro ha publicado un artículo explicando como compilar y depurar un plugin de ejemplo para gvSIG 2.1 con NeatBeans. He adaptado sus instrucciones para Eclipse que es mi IDE habitual. Este artículo no es tan detallado como el suyo así que seguramente tendrás que consultar los dos, especialmente los pasos previos que comenta Joaquín para que todo funcione.

Una vez que tenemos los «previos» realizados, creamos un nuevo workspace en eclipse, por ejemplo workspace-gvsig-landregistry.

Nos aseguramos de que tenemos instalados en eclipse:

Abrimos la perspectiva de eclipse de SVN Repository Exploring, desde Window -> Open perspective -> Other, o cualquier otro de los sitios desde los que se puede abrir.

Y añadimos el repositorio del plugin desde File -> New -> Repository Location o el icono correspondiente. Como URL usaremos:

http://devel.gvsig.org/svn/gvsig-plugintemplates/org.gvsig.landregistryviewer/trunk/org.gvsig.landregistryviewer/

Seleccionamos el repositorio que acabamos de añadir y en el menú contextual escogemos Check out as maven project

Si no tenemos el conector de maven-svn instalado, nos pedirá instalarlo. En la ventana previa al checkout nos aseguraremos de que la opción «All projects» está activada

Puede tardar un ratito en descargar, sobre todo si tiene que descargar muchas dependencias. Cuando acabe, pasamos a la perspectiva Java y ya tendremos los proyectos correspondientes al plugin configurados en el workspace.

Si no tienes la opción de Build automatically activada, haz un build all. A continuación pon un punto de ruptura para comprobar que todo funciona correctamente en el punto que indica Joaquín (método createWindow de la clase LandRegistryViewerExtension).

Tras lanzar gvSIG en modo debug,


./gvSIG --debug --pause

configuramos el debugger. En Debug Configurations, añadiremos una nueva configuración del tipo Remote Java Application

En name pondremos lo que queramos, por ejemplo org.gvsig.landregistryviewer.app, en project org.gvsig.landregistryviewer.app.mainplugin y en port 8765. Si antes de crear la configuración de debug seleccionamos el proyecto org.gvsig.landregistryviewer.app.mainplugin en el package explorer nos rellenará automáticamente name y project.

Al darle a debug debería abrirse gvSIG y pararse la ejecución en el punto que hemos marcado.

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

 

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