Personal tools
gvSIG Desktop
gvSIG Desktop
 
Document Actions

Estructura de un proyecto en gvSIG

by Joaquin Jose del Cerro Murciano last modified 2010-08-31 14:00

Maven y eclipse

Una de las características más interesantes de maven es su capacidad de trabajo con proyectos multimódulo y las facilidades que ofrece a la hora de ejecutar objetivos predefinidos para realizar ciertas tareas claramente definidas, como la compilación del código y su empaquetado.

En su contra, la versión actual de Eclipse no incorpora los mecanismos necesarios para poder soportar los proyectos multimódulo, por lo que la integración con los mecanismos de maven resultan complejos y requieren el uso de determinados mecanismos y estrategias para conseguir simular dichos comportamientos.

Maven utiliza un Project Object Model (POM) para describir el proyecto de software a construir, la estructura del proyecto y sus submódulos, sus dependencias de otros módulos y componentes externos y el orden de construcción de los elementos. Haciendo uso de estas características definidas, se puede llegar a conseguir que eclipse emplee la información que en los POMs se detalla, para simular un comportamiento multimódulo.

Trabajar en eclipse con maven

A la hora de trabajar con eclipse, tal y como se mencionaba anteriormente, habrá que tener en cuenta unas pautas que nos permitirán hace uso de las funcionalidades que maven nos ofrece.

Lo primero que llama la atención es la nomenclatura de los directorios. Los nombres aplicados a los directorios no son casuales, y es que a través de ellos, se pretende simular la estructura jerárquica del proyecto. Para ello, el proyecto padre tendrá el nombre del artifact_id y, a partir de él, sus submódulos completarán su nombre con el del padre (es decir, si tengo el proyecto padre org.gvsig.ejemplo, el submódulo Ejemplo1 deberá estar contenido en el directorio 'org.gvsig.ejemplo/org.gvsig.ejemplo.ejemplo1', el Ejemplo2 en 'org.gvsig.ejemplo/org.gvsig.ejemplo.ejemplo2', si el Ejemplo1 tuviera a su vez el submódulo Ejemplo1a estaría en 'org.gvsig.ejemplo/org.gvsig.ejemplo.ejemplo1/org.gvsig.ejemplo.ejemplo1a', y así sucesivamente). Esto da pie a una estructura del proyecto en forma de árbol:

  • org.gvsig.ejemplo
    • org.gvsig.ejemplo.ejemplo1
      • org.gvsig.ejemplo.ejemplo1.ejemplo1a
    • org.gvsig.ejemplo.ejemplo2

Los nodos padre no son tomados como proyectos Java por eclipse, ya que simplemente son los contenedores de los submódulos. Estos proyectos contendrán el fichero POM con su definición y la descripción de los submódulos que lo conforman. De esta forma, se puede lanzar órdenes a módulo padre, para que se ejecute en él y en todos sus descendientes de manera automática (install, compile, etc.)

Por su parte, los nodos hijos (u hojas del árbol) sí que son proyectos Java, con su estructura habitual en proyectos de este tipo. Estos nodos pueden aprovechar la configuración del padre (dependencias, propiedades, atributos, ...) si especifica en su POM quién es su padre, simplificando su configuración.

Desarrollar un proyecto para gvSIG

Cuando vamos a desarrollar un proyecto para gvSIG deberíamos tener una separacion lo más estricta posible entre el API y la implementación de ese API. Para llevar esto a cabo, y apoyándonos en la facilidad de maven para gestionar proyectos multimódulo se ha confeccionado una plantilla base para un proyecto de gvSIG. Esta plantilla nos orientará sobre cómo organizar el proyecto, separando de forma estricta en varios proyectos de eclipse y distintos jars la lógica de nuestra extensión, del interface de usuario y a su vez, el API de la lógica de su implementación y el API del interface de usuario de su implementación.

La estructura base de un proyecto de será:

  • library
    • tags
    • branches
    • trunk
      • org.gvsig.example
        • org.gvsig.example.lib
          • org.gvsig.example.lib.api
          • org.gvsig.example.lib.spi
          • org.gvsig.example.lib.impl
        • org.gvsig.example.prov
          • org.gvsig.example.prov.provider1
        • org.gvsig.example.swing
          • org.gvsig.example.swing.api
          • org.gvsig.example.swing.impl
        • org.gvsig.example.main
  • extensión
    • tags
    • branches
    • trunk
      • org.gvsig.example.app
        • org.gvsig.example.app.extensión

En un primer momento, y viendo esta estructura, si lo comparabamos con lo que normalmente se venía haciendo en gvSIG antes de 2.0, parece una estructura del proyecto bastante compleja, pero veamos con un poco de detalle en que consiste esta.

Lo primero que observamos es que el proyecto está orientado como un proyecto de SVN multimódulo en comparación con lo que solíamos encontrarnos en los desarrollos de gvSIG 1.X. Por un lado tenemos el desarrollo de la parte de librería y por otro, el de la extensión o extensiones para gvSIG. Esto se ha organizado así ya que normalmente los cambios en la lógica de nuestra extensión suelen llevar un ciclo de vida claramente separados de la integración de estos en gvSIG. Una vez desarrollada la extensión es fácil que de una versión a otra de gvSIG tengamos que hacer alguna modificación en la parte de nuestro código que contiene la integración con gvSIG mientras que la parte de lógica no sufra cambios a no ser que se traten de correcciones de bugs. Para conseguir esta independencia, el repositorio del SVN se separa en dos grandes grupos:

  • library

    Contendrá la parte de lógica e interface de usuario que son independientes de gvSIG como aplicación. No quiere decir que no dependan de algunas librerías de gvSIG como la de acceso a datos, geometrías o mapcontext. SI necesitan depender de ellas puede hacerlo.

  • extensión.

    Aquí estará la parte de nuestro código que tiene dependencias con la aplicación gvSIG, andami y otras extensiones de gvSIG. Aquí estarán nuestras clases Extension así como la configuración de nuestro plugin para andami.

Vamos a ver ahora que nos encontramos dentro de library. Aquí residirán

  • org.gvsig.example.lib

    Nos proporcionará el API, SPI y la implementación de ese API.

  • org.gvsig.example.prov

    En caso de que nuestra librería necesite trabajar con algún proveedor de servicios aquí estarán las distintas implementaciones de estos proveedores de servicios.

  • org.gvsig.example.swing

    En caso de que nuestro proyecto suministre un interface de usuario para la parte de lógica, este lo ubicaremos aquí. La parte de org.gvsig.example.lib no debería contener dependencias con el interface de usuario. Este estará sólo aquí.

  • org.gvsig.example.main

    Lo primero que podemos pensar es ¿ qué hace aquí un módulo main dentro de la librería ? Pues aunque parezca extraño tiene su utilidad. Se trata de un módulo destinado a proveer una aplicación de prueba que permita arracar el interface de usuario y la lógica de la librería sin tener que arrancar un gvSIG para probarlo. Esto es muy útil de cara a poder realizar un desarrollo más ágil de nuestro proyecto y posponer la integración con gvSIG hasta que este esté en fases de desarrollo avanzadas.

Y por último nos encontramos con la separación en algunos de estos módulos entre API, SPI e implementación. Esta separación podemos encontrarla en org.gvsig.example.lib y org.gvsig.example.swing.

Supongamos que nos encontramos con el desarrollo de una extensión de análisis de redes en gvSIG. ¿ Con qué proyectos nos encontraríamos ?

En principio nuestro proyecto no precisa de proveedores de servicios especiales. Tiene una parte de lógica, y una parte de interface de usuario, además del propio plugin para gvSIG. Tendríamos los siguientes proyectos:

  • org.gvsig.networkAnalysis.lib.api
  • org.gvsig.networkAnalysis.lib.impl
  • org.gvsig.networkAnalysis.swing.api
  • org.gvsig.networkAnalysis.swing.impl
  • org.gvsig.networkAnalysis.main
  • org.gvsig.networkAnalysis.app.extensión

Básicamente tendríamos estos seis proyectos, y cada uno de ellos generaría su propio jar, acorde con el nombre del proyecto. Además de que cada uno de los proyectos estará en su carpeta correspondiente, es importante que tengan el nombre adecuado. Esto es así ya que al importar estos proyectos dentro de eclipse, nos encontraremos con que el árbol de carpetas es aplanado, pero gracias a la elección de los nombres de los proyectos estos mantendrán su coherencia dentro de nuestro workspace.

Aunque parezca obvio, conviene recalcar que dependencias son aceptables entre estos proyectos. Habrá un dependencia desde la implementación hacia el API, pero no al revés. Así mismo, nuestro API debe ser conciso y completo. completo por que el cliente de ese API no debe necesitar conocer de la implementación para poder usarlo, y conciso, por que no debe exponer los detalles de implementación; cuanto menos exponga y más reducido se mantenga, más fácil y seguro será su mantenimiento.

Por otro lado, tenemos el interface de usuario. Este, sea la implementación o su API, no deberá tener dependencias con la implementación de la librería, la lógica. Sólo deberá depender de su API.

Y por ultimo, la aplicación de pruebas y la extensión sólo deberan tener dependencias con el API de la librería y el API del interface de usuario.

Hacer notar también, que en cada uno de los distintos niveles de carpetas encontraremos ficheros pom.xml. Así tendremos un pom en org.gvsig.example que nos permitirá hacer operaciones con todos los submódulos de nuestro proyecto, así como contener la configuración general del proyecto. Por ejemplo, podremos construir los proyectos de eclipse de cada uno de nuestros módulos directamente, atacando a este pom. A su vez, org.gvsig.example.lib y org.gvsig.example.swing tendrán sus propios ficheros pom con su configuración específica. Por último cada uno de los proyectos finales tendrán su propio fichero pom. Cada uno de estos pom estará configurado indicando como pom padre el de la capeta superior para heredar de él la configuración comúm.

En varios momentos hemos estado hablando del API. Pero...

¿ qué entendemos por el API ?

¿ Cómo lo definimos ?

La pregunta no es tan obvia como parece. Cuando le pides a varios desarrolladores que definan el API de un módulo no es normal que tengas resultados similares. Así que en gvSIG ¿ qué esperamos cuando hablamos que hay una definición del API ? Normalmente el API estará formado por un juego de interfaces java. Puede haber alguna clase abstract que presenta una implementación por defecto para algo que debe ser extendido por el consumidor de ese API, pero nunca contendrá una clase con su implementación. La excepción a esto suelen ser las excepciones. Por su naturaleza, las excepciones que dispara ese API estarán implementadas en el API. Este juego de interfaces, se empaqueta en un proyecto y su jar y es la única dependencia con el proyecto que debe de tener un consumidor de este.

A la hora de manejarnos con swing nos vamos a encontrar algunas variaciones. Debido a la falta de interfaces en swing para manejar los componentes gráficos cuando vayamos a definir el API de la parte de swing de nuestro proyecto en lugar de usar interfaces, usaremos clases abstractas que extenderán los distintos componentes swing, añadiendo métodos abstractos propios del dominio de nuestro proyecto. Será normal encontrarnos clases abstractas que extiendan a JPanel, de forma que estos definan los interfaces de usuario asociados a componentes de nuestro proyecto.

¿ Y qué tendremos en la implementación ?

Pues allí tendremos un juego de clases que implementan los interfaces definidos en el API. Normalmente existirá un manager que hará las veces de punto de entrada a las funcionalidades de nuestro proyecto, de factoría y configuración de este.

Es conveniente repasar las herramientas que nos proporciona org.gvsig.tools para la gestión de la separación entre API e implementación usando los Library, Locators y Manager, y si nuestro proyecto va a precisar de proveedores de servicios las utilidades que existen para su gestión, de forma que cada proyecto no reinvente cada vez como implementarlos y en todo gvSIG se traten de forma homogénea.

También deberemos tener en cuenta las recomendaciones a la hora de nombrar las clases e interfaces. La estructura de proyecto descrita está pensada para adecuarse a una nomenclatura como la descrita en el documento Nomenclatura para clases e interfaces. Así los interfaces que encontremos en el API se nombrarán usando nombres significativos del dominio de nuestra extensión, sin utilizar ningun tipo de prefijo o sufijo; mientras que las clases que encontremos en el proyecto de implementación y aporten la implementación de alguno de los interfaces del API se nombrarán anteponiendo Default al nombre del interface que implementan.

Antes de abordar la creación de un proyecto gvSIG de acuerdo a la estructura descrita es aconsejable repasar la documentación sobre org.gvsig.tools.service que describe con mas detalle las clases e interfaces a crear, y en qué subproyecto de maven residen.

View source document Get permanent link


Powered by Plone CMS, the Open Source Content Management System

This site conforms to the following standards: