Personal tools
gvSIG Desktop
gvSIG Desktop

Cached time 11/22/13 07:46:15 Clear cache and reload

 
Document Actions

La librería con la lógica

by Joaquin Jose del Cerro Murciano last modified 2012-03-12 15:23
La parte de la lógica de nuestro desarrollo la encontraremos dividida en dos proyectos:

- org.gvsig.visor.lib.api

- org.gvsig.visor.lib.impl


En el proyecto del API encontraremos principalmente interfaces. Estos interfaces compondrán
el API de los componentes de lógica que precisemos desarrollar. 
EL modelo de clases del ejemplo es el que se muestra en el siguiente diagrama:

.. figure:: ../data/org.gvsig.visor.api.png
   :align: center

   Modelo de clases del API
   
Tendremos las siguientes entidades:

- **VisorLibrary**, que representa al objeto *Library*. De esta clase señalar los métodos:

  - *doRegistration*, que se ejecuta al cargar la librería e informa qué clase de librería
    es, en nuestro caso la definición de un API, así como qué otras librerías requiere que estén
    inicializadas antes que esta, la librería de acceso a datos, y la de geometrías. El código
    que hace esto es:

    .. code-block:: java

      public void doRegistration() {
        this.registerAs(VisorLibrary.class, Library.TYPE.API);
        this.require(DALLibrary.class);
        this.require(GeometryLibrary.class);
      }

  - *doPostInitialize*, que se ejecuta cuando se han inicializado todas las librerías.
    En nuestro caso realiza comprobaciones para verificar que al menos una implementación
    del API ha sido registrada. El código que hace esto es:
  
    .. code-block:: java

      protected void doPostInitialize() throws LibraryException {
        // Validate if there are any implementation registered.
        VisorManager manager = VisorLocator.getManager();
        if (manager == null) {
            throw new ReferenceNotRegisteredException(
                VisorLocator.MANAGER_NAME, VisorLocator.getInstance()
              );
        }
      }

  
  .. note TODO: Comentar algo sobre la referencia al META-INF/services

- **VisorLocator**, es el *locator* de nuestra librería, el encargado de
  suministrarnos la instancia de nuestro manager. Se trata de una clase con métodos
  estáticos para registrar implementaciones de este API u obtener una implementación
  de él.

- **VisorManager**. Un interface. El del manager de la librería. Define métodos para obtener las
  manzanas y parcelas así como para localizar una manzana dado un punto. Es la
  entrada a las distintas entidades de nuestro modelo.

- **VisorBlock**. Un interface que representa a una manzana, y aporta métodos para obtener la geometría
  que define la manzana o para obtener las parcelas que la constituyen.

- **VisorProperty**. Un interface que representa una parcela catastral. Tiene métodos para obtener
  la geometría que la define, su código o municipio.

Vamos a ver qué nos encontramos en la parte de implementación. Observaremos que
mientras que en el API lo normal ha sido encontrarnos interfaces, en la implementación
nos encontraremos clases. Clases que implementan los distintos interfaces que se
definieron en el API.  Por convenio, a la implementación de los distintos interfaces
que aparecen en el API las llamaremos igual que en el API anteponiéndole el prefijo *Default*.

El modelo de clases de la implementación para nuestro ejemplo es:

.. figure:: ../data/org.gvsig.visor.impl.png
   :align: center

   Modelo de clases de la implementación
   
Vamos a ir viendo las partes más relevantes de la implementación. 

- **VisorDefaultImplLibrary**. Al igual que en el API, esta clase se encarga de
  inicializar la librería de la implementación. De esta clase señalar los métodos:
  
  - *doRegistration*, que se encarga de registrar la librería como una implementación
    del API de *VisorLibrary*. Si tuviese otras dependencias distintas de las marcadas en el 
    API, se añadirían aquí para asegurarnos que esas librerías se inicializan antes
    que esta, pero no es el caso de nuestro ejemplo. Al registrar esta librería como
    una implementación de *VisorLibrary*, se cubren dos funciones. Por un lado la librería
    del API será inicializada siempre antes que esta implementación, y por otro lado
    cuando alguna otra librería fije dependencias con el API, el mecanismo de inicialización
    de librerías se encargará de inicializar la implementación junto con el API para 
    asegurarnos de que dispondremos de una implementación del API que hemos requerido.
    El código que necesitaremos poner en nuestro ejemplo será:

    .. code-block:: java

      public void doRegistration() {
        this.registerAsImplementationOf(VisorLibrary.class);
      }

  - *doInitialize*, que se encarga de registrar en el locator del API la implementación
    del manager que tenemos en esta librería. El código que hace esto es:  

    .. code-block:: java

      protected void doInitialize() throws LibraryException {
          VisorLocator.registerManager(DefaultVisorManager.class);
      }

- **DefaultVisorManager**. De esta clase conviene resaltar principalmente:

  - El método *getBlock*. Podemos ver cómo realizar una busqueda de un registro
    filtrando por una condición espacial:    

    .. code-block:: java

      try {
        String attrGeomName = blocks.getDefaultFeatureType().getDefaultGeometryAttributeName();
        FeatureQuery query = blocks.createFeatureQuery();
        query.setFilter( new IntersectsEvaluator(attrGeomName,point) );
        set = blocks.getFeatureSet(query);
        if( set.isEmpty() ) {
          return null;
        }
        it = set.fastiterator();
        Feature f = (Feature) it.next();
        VisorBlock block = new DefaultVisorBlock(this,f.getGeometry(attrGeomName));
        return block; 
      } catch (DataException e) {
        ...
      } finally {
        if( it != null ) {
          it.dispose();
        }
        if( set != null ) {
          set.dispose();
        }
      }
      
    
    ..  Tip::
        Puede encontrar información sobre los mecanismos
        disponibles para el acceso a datos consultando la
        `Guía para el desarrollador de la Librería de Acceso a Datos (DAL)`_ 

    .. _`Guía para el desarrollador de la Librería de Acceso a Datos (DAL)` : https://gvsig.org/web/reference_catalog/lookupObject?uuid=b676641c65b75fd97c3f1cedb8482073

    De aquí resaltar:
    
    - Podemos averiguar qué atributo de la *feature* es el que contiene la geometría 
      a través del *getDefaultGeometryAttributeName* del *feature type* de nuestro *store*.
    
    - Para realizar una búsqueda de *features* en un *store* lo haremos invocando al método
      *getFeatureSet* pasando como parámetro una instancia de *FeatureQuery* en la que se
      especifiquen las condiciones de filtrado. En ella también se pueden especificar 
      orden o atributos que queremos recuperar en nuestra query.
  
    - La condición de filtro se especifica suministrando un Evaluator al método *setFilter*
      de nuestra query.
    
    - Debemos encargarnos de liberar los objetos que creemos, como son *iteradores* o *feature sets*.
      Hay que tener en cuenta que dependiendo del tipo de *store* con el que estemos trabajando
      estos pueden tener reservados recursos como conexiones a BBDD, recordsets o conexiones a
      servidores remotos.
      
  - El método *openShape*. Aquí podemos ver cómo abrir un *store* basado en shapes
    ya existentes:

    .. code-block:: java

      parameters = manager.createStoreParameters("Shape");
      parameters.setDynValue("shpfile", shape);
      parameters.setDynValue("crs", "EPSG:23030");
      return (FeatureStore) manager.openStore("Shape", parameters);

    Observaremos que para abrir un *store* lo realizaremos en dos fases. Por un lado crearemos
    una estructura para albergar los parámetros necesarios para abrir nuestro *store*, la
    inicializaremos con los valores adecuados e invocaremos al método *openStore* del manager
    de acceso a datos con esos parámetros.
    
    Cada tipo de *store* tendrá un juego de parámetros específicos de él. Para abrir un shape, 
    deberemos indicarle como mínimo el nombre del fichero y el sistema de referencia en el que
    se encuentra.
    
- **IntersectsEvaluator**. Se trata de la clase que evalúa la condición usada en el filtro.
  Esta clase comprueba si el campo geometría especificado de una feature dada intersecta con
  una geometría concreta. En su construcción se le suministran el campo que contiene la
  geometría de la feature y la geometría con la que hay que comprobar si intersecta. De esta 
  clase conviene resaltar:
  
  - el método *evaluate*, encargado de realizar la comprobación:

    .. code-block:: java
  
      Geometry op1geom = (Geometry) data.getDataValue(this.op2attrname);
      return new Boolean(this.op1geom.intersects(op1geom));

    Sabiendo cómo se llama el atributo que contiene la geometría podemos obtener esta
    a través del método *getDataValue*. Una vez tenemos las dos geometrías podemos
    invocar el método *intersecs* de la geometría para comprobar si intersectan.
    
  - El método *getCQL*. Este método devolverá una cadena siguiendo el formato de un *where* de
    sql a utilizar como filtro en *stores* que ataquen a la BBDD sql. El filtro devuelto puede 
    no ser exactamente el mismo que el implementado por el código del método *evaluate*, actuando
    a modo de filtro previo a este siempre que el store lo soporte.
    
    
- **DefaultVisorBlock**. Representa a una manzana de nuestro dominio. Almacena la 
  geometría que da forma a la manzana. La parte más relevante de esta clase es el
  método *getProperties* que retorna todas las parcelas que se encuentran sobre
  esa manzana:

  .. code-block:: java

    List properties = new ArrayList();		

    FeatureStore store = this.manager.getProperties();
    String attrGeomName = store.getDefaultFeatureType().getDefaultGeometryAttributeName();
    FeatureQuery query = store.createFeatureQuery();
    query.setFilter( new IntersectsEvaluator(attrGeomName, this.shape) );
    set = this.manager.getProperties().getFeatureSet(query);
    if( set.isEmpty() ) {
      return null;
    }
    it = set.fastiterator();
    while( it.hasNext() ) {
      Feature f = (Feature) it.next();
      VisorProperty property = new DefaultVisorProperty(
        this.manager,
        f.getString(PROPERTIES_CODE),
        f.getGeometry(attrGeomName),
        f.getInt(PROPERTIES_CREATIONDATE),
        f.getInt(PROPERTIES_MUNICODE)
      );
      properties.add(property);
    }
    return properties;

  Podemos observar que utiliza el mismo mecanismo para filtrar las parcelas que
  usa el manager para recuperar un manzana. En este caso una vez a conseguido el *set*
  con las parcelas, lo recorre, recuperando los datos de estas y creando los
  objetos parcela.

- **DefaultVisorProperty**. Se trata de la clase que representa a un parcela. En nuestro 
  ejemplo no tiene apenas lógica, limitándose a almacenar los datos y exponerlos mediante
  *geters*.
  

View source document

View source document Get permanent link


Powered by Plone CMS, the Open Source Content Management System

This site conforms to the following standards: