Usando GeoProcesos en gvSIG desde Java

Posted: Septiembre 4th, 2016 | Author: | Filed under: Sin categoría | Tags: , , , , , , , , | No Comments »

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:

1
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:

1
2
3
4
5
6
7
8
9
10
11
<dependency>
    <groupId>org.gvsig</groupId>
    <artifactId>org.gvsig.geoprocess.lib.api</artifactId>
    <version>2.2.66</version>
</dependency>

<dependency>
    <groupId>org.gvsig</groupId>
    <artifactId>org.gvsig.geoprocess.lib.sextante</artifactId>
    <version>2.2.66</version>
</dependency>

y al config

1
<depends plugin-name="org.gvsig.geoprocess.app.sextante"/>

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:

1
2
3
4
String ALG_NAME = "gvSIG-intersection";
SextanteGeoProcessManager manager = (SextanteGeoProcessManager) GeoProcessLocator.getGeoProcessManager();
HashMap<String, GeoAlgorithm> 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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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:

1
2
3
4
5
<dependency>
    <groupId>org.gvsig</groupId>
    <artifactId>org.gvsig.geoprocess.algorithm.intersection</artifactId>
    <version>2.2.66</version>
</dependency>

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:

1
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:

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

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

Posted: Abril 30th, 2014 | Author: | Filed under: Sin categoría | Tags: , , , , , , , , | 2 Comments »

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?