Rss Feed

OpenScales, BlazeDS et JTS

Afin de faciliter les opérations d’enregistrement et de récupération de données géométriques il est d’usage d’utiliser la librairie Java JTS dont les types de géométrie peuvent être directement enregistrés en base de donnée (Oracle ou PostgreSQL+Postgis) grâce, par exemple, à Hibernate Spatial. C’est le format utilisé en standard par la librairie Geotools. Malheureusement il existe un problème dans BlazeDS qui conduit à une mauvaise sérialisation/dessérialisation des objets JTS, ceux-ci ne contiennent aucune propriété valable après avoir été traités par le marshaller ; il est dont impossible de les faire transiter en l’état entre le client et le serveur. Grâce à l’utilisation des BeanProxy et du PropertyProxyRegistry nous avons pu redéfinir la liste des propriétés à considérer pour les objet de type com.vividsolutions.jts.geom.Point et com.vividsolutions.jts.geom.Polygon ; et ainsi modifier la façon dont elles sont traitées (en overridant les méthodes getValue et setValue de la class BeanProxy). Les objets de type géométrie transitent donc en toute transparence entre l’application Flex/Flash et l’application serveur+BDD. Ceci est particulièrement util pour le dessin sur carte avec sauvegarde des objets géométriques créés par l’utilisateur et apporte un gain de temps considérable dans la réalisation d’un projet avec module cartographique.

Exemple pour Polygon :

PropertyProxyRegistry.getRegistry().register(com.vividsolutions.jts.geom.Polygon.class, new BlazeDSGeometryUtils.JTSPolygonProxy());

static class JTSPolygonProxy extends BeanProxy
{
@Override
public List getPropertyNames(Object instance)
{
List newList = new ArrayList();
newList.add("SRID");
newList.add("area");
newList.add("coordinate");
newList.add("coordinates");
newList.add("numPoints");
newList.add("dimension");
newList.add("length");
newList.add("geometryType");

return newList;
}
}

Cas des systèmes de projection :

La librairie OpenScales n’offre pas autant de méthodes de projection de coordonnées que Geotools ; il peut être utile d’effectuer les conversions d’un système de projection à un autre directement sur le serveur pour s’affranchir des limitations imposées par OpenScales. On peut citer par exemple le système Lambert II étendu qui n’est supporté que dans la dernière version d’OpenScales — réservée à Flex 4. Pour éviter de fastidieuses et répétitives tâches de conversion au sein des fonctions d’enregistrement et de requêtage nous avons choisi de les implémenter directement dans la redéfinition des fonctions du BeanProxy. En effet, en déclarant à BlazeDS les propriétés des objets Point et Polygon il est tout à fait possible d’en ajouter plus que nécessaire, et notamment une propriété contenant le code du système de projection voulu après la sérialisation/désérialisation. Il suffit alors, dans la surcharge des méthodes setValue et getValue, d’agir sur les coordonnées en fonction du système désiré. De cette manière nous pouvons travailler en coordonnées Long/Lat dans l’application Flex et enregistrer les données en système métrique — Lambert II étendu ou 93 par exemple — dans lequel une requête portant sur la distance entre plusieurs points sera nettement moins coûteuse en ressources.

Apache CXF et Hibernate hbm2java

L’utilisation de Apache CXF/JAX-RS pour la création de services REST passe par l’ajout d’annotations dans vos POJOs ce qui peut être contraignant quand ceux-ci sont générés depuis vos fichiers hbm via hbm2java. Heureusement il existe une solution à ce problème via l’utilisation de freemarker. Freemarker est une librairie de génération de template utilisée par hbm2java pour transformer les xml de mapping (.hbm) en POJOs java. Prenons par exemple l’annotation @XmlRootElement qui doit précéder tous les pojos que jax-rs va transformer en XML :

Dans votre target ANT hbm2java ajouter templatepath=“resources/META-INF/pojo_templates/“ avec pojo_templates le répertoire qui contiendra les templates freemarker modifiées.

Dans  resources/META-INF/pojo_templates/ créer un fichier ‘PojoTypeDeclaration.ftl’ avec le contenu suivant :

<#if pojo.hasMetaAttribute("xmlrootelement")>

import javax.xml.bind.annotation.XmlRootElement;

</#if>

/**

${pojo.getClassJavaDoc(pojo.getDeclarationName() + " generated by hbm2java", 0)}

*/

<#include "Ejb3TypeDeclaration.ftl"/>

<#if pojo.hasMetaAttribute("xmlrootelement")>

@XmlRootElement(name="${pojo.getMetaAsString("xmlrootelement")}")

</#if>

${pojo.getClassModifiers()} ${pojo.getDeclarationType()} ${pojo.getDeclarationName()} ${pojo.getExtendsDeclaration()} ${pojo.getImplementsDeclaration()}

Il suffit alors d’ajouter dans votre fichier .hbm un meta attribute indiquant le nom du POJO. Exemple :

<hibernate-mapping package=“com.pojos”>

<class name=“MaClass” table=“ma”_table>

<meta attribute="xmlrootelement">MaClass</meta>

...

Le POJO généré sera alors de la forme :

import javax.xml.bind.annotation.XmlRootElement;

/**

* MaClass generated by hbm2java

*/

@XmlRootElement(name=“MaClass”)

public class MaClass  implements java.io.Serializable { ... }


On peut biensur appliquer ce principe à d’autres annotations (XmlSeeAlso …) et à d’autres frameworks.

Apache Cassandra

Dans le cadre d’un projet interne R&D nous avions besoin d’un système permettant de stocker un nombre très important de données tout en conservant des temps d’accès très court pour les recherches. Après plusieurs essais, il était évident qu’une base de donnée relationnelle standard comme MySQL ne pouvait répondre à notre besoin : même avec un bon choix d’index les ressources matérielles demandées pour gérer des tables contenant des centaines de millions d’enregistrement étaient trop importantes.

Nous nous sommes donc tournés vers Apache Cassandra à l’origine développé par Facebook derrière un index lucene.

Architecture de la base Apache Cassandra :

- un keyspace dans cassandra contient un ensemble non fini de lignes

- chaque ligne posséde 2 familles de colonnes

- chaque famille de colonne possède un ensemble non fini de super colonnes (en moyenne 30 000 super colonnes)

- chaque super colonne possède un ensemble non fini de colonnes (en moyenne une cinquantaine)

- chaque ligne possède un index Lucene qui lui est propre

- chaque valeur de colonne est indexée dans Apache Lucene

En ne comptant qu’une seule famille de colonne et une centaine de lignes on arrive déjà à 150 000 000 de cellules.

Cassandra étant un système NoSQL, il n’est pas possible de faire des requêtes complexes sur les valeurs stockées et ce n’est d’ailleurs pas le but. Grâce à la conjonction de Lucene et d’une API JAVA complète que nous avons développé en interne cela devient un non problème, Lucene offrant des fonctions très pratiques telles que le must/should, le classement par pertinence.

Les tests effectués révèlent des temps d’accès aux données très rapides (de quelques millisecondes) malgré le quantité, là où MySQL Cluster mettait plusieurs secondes.