Les chapitres précédents utilisaient des méthodes statiques de Apache SIS par commodité. Dans certains cas, il est possible de remplacer ces méthodes statiques par du code ne faisant appel qu’à des méthodes de GeoAPI. Ces remplacements peuvent être intéressants pour les applications qui souhaiteraient limiter les dépendances directes envers Apache SIS, par exemple afin de faciliter d’éventuelles migrations entre SIS et d’autres implémentations de GeoAPI. Mais cela peut amener ces applications à écrire leur propres méthodes de commodités. Les sections suivantes donnent quelques pistes pour faciliter cette tâche.
Pour chaque classe, méthode et constante définie à partir d’un standard OGC ou ISO,
GeoAPI indique sa provenance à l’aide d’annotations définies dans le paquet org.opengis.annotation
.
Cette correspondante est décrite dans le chapitre à propos de GeoAPI.
Les méthodes d’introspections du Java permettent d’accéder à ces informations pendant l’exécution d’une application.
La classe org.apache.sis.util.iso.Types
fournit des méthodes de commodités telles que
getStandardName(Class)
à cette fin, mais on peut éviter ces méthodes.
L’exemple suivant affiche le nom standard de la méthode getTitle()
de l’interface Citation
:
Class<?> type = Citation.class;
Method method = type.getMethod("getTitle
", (Class<?>[]) null);
UML annot = method.getAnnotation(UML.class);
String id = annot.identifier();
System.out.println("Le nom standard de la méthode " + method.getName() + " est " + id);
L’opération inverse — obtenir la classe et méthode Java d’un nom standard — est un peu plus lourde.
Elle nécessite la lecture du fichier class-index.properties
fournit dans le
paquet org.opengis.annotation
. L’exemple suivant lit ce fichier juste avant
de rechercher le nom de l’interface correspondant à CI_Citation
.
Toutefois les utilisateurs sont encouragés à ne lire ce fichier qu’une fois et de conserver son contenu dans
une cache de leur application.
Properties isoToGeoAPI = new Properties();
try (InputStream in = UML.class.getResourceAsStream("class-index.properties
")) {
isoToGeoAPI.load(in);
}
String isoName = "CI_Citation
";
String geoName = isoToGeoAPI.getProperty(isoName);
Class<?> type = Class.forName(geoName);
System.out.println("L’interface GeoAPI pour le type ISO " + isoName + " est " + type);
La méthode de commodité de org.apache.sis.util.iso.Types
correspondante à cette operation est
forStandardName(String)
.
GeoAPI définit des fabriques (Factory
) permettant de créer des implémentations de ses interfaces.
Par exemple DatumFactory
fournit des méthodes permettant de créer des instances
implémentant les interfaces du paquet org.opengis.referencing.datum
.
Ces Factory
doivent être implémentées par les bibliothèques géospatiales
et déclarées comme services tel que défini par la classe standard java.util.ServiceLoader
.
La javadoc de ServiceLoader
explique la façon de procéder.
Mais pour résumer, les bibliothèques doivent créer dans le répertoire META-INF/services/
un fichier dont le nom correspond au nom complet de l’interface de la fabrique
(org.opengis.referencing.datum.DatumFactory
dans l’exemple précédent).
Ce fichier texte doit contenir sur une ligne le nom complet de la classe implémentant cette interface.
Il peut s’agir d’une classe cachée aux yeux des utilisateurs, car ils n’ont pas besoin de connaître son existence.
Si la bibliothèque a bien déclaré ses fabriques comme des services, alors
les utilisateurs peuvent les obtenir en utilisant ServiceLoader
comme dans l’exemple ci-dessous.
Cet exemple ne prend que la première fabrique trouvée; s’il existe plusieurs fabriques,
par exemple lorsque plusieurs bibliothèques cohabitent, alors le choix est laissé à l’utilisateur.
import org.opengis.referencing.GeodeticDatum;
import org.opengis.referencing.DatumFactory;
import java.util.ServiceLoader;
public class MyApplication {
public void createMyDatum() {
ServiceLoader loader = ServiceLoader.load(DatumFactory.class);
DatumFactory factory = loader.iterator().next();
GeodeticDatum myDatum = factory.createGeodeticDatum(…);
}
}
Implémenter soi-même GeoAPI n’est pas si difficile si on se contente de besoins bien précis. Un développeur peut se concentrer sur une poignée d’interfaces parmi les centaines de disponibles, tout en disposant des autres interfaces comme autant de points d’extensions à éventuellement implémenter au gré des besoins.
Le modèle conceptuel représenté par les interfaces est complexe. Mais cette complexité peut être réduite en combinant certaines interfaces.
Par exemple plusieurs bibliothèques, même réputées, ne font pas la distinction entre Système de coordonnées (CS)
et Système de référence des coordonnées (CRS).
Un développeur qui lui non-plus ne souhaite pas faire cette distinction peut implémenter ces deux interfaces par la même classe.
Il peut en résulter une implémentation dont la hiérarchie de classes est plus simple que la hiérarchie des interfaces de GeoAPI.
Le module geoapi-examples
, discuté plus loin, fournit de telles combinaisons.
Le tableau suivant énumère quelques combinaisons possibles:
Interface principale | Interface auxiliaire | Usage |
---|---|---|
CoordinateReferenceSystem |
CoordinateSystem |
Description d’un système de référence spatial (CRS). |
GeodeticDatum |
Ellipsoid |
Description d’un référentiel geodétique. |
CoordinateOperation |
MathTransform |
Opération de transformation de coordonnées. |
IdentifiedObject |
ReferenceIdentifier |
Objet (typiquement un CRS) que l’on peut identifier par un code. |
Citation |
InternationalString |
Référence bibliographique composée d’un simple titre. |
GeographicBoundingBox |
Extent |
Étendue spatiale en degrés de longitude et de latitude. |
ParameterValue |
ParameterDescriptor |
Description d’un paramètre (nom, type) associée à sa valeur. |
ParameterValueGroup |
ParameterDescriptorGroup |
Description d’un ensemble de paramètres associés à leurs valeurs. |
Le module geoapi-examples
fournit des exemples d’implémentations simples.
Plusieurs de ces classes implémentent plus d’une interface à la fois afin de proposer un modèle conceptuel plus simple.
La Javadoc de ce module
énumère les paquets et classes clés avec les combinaisons effectuées.
Ce module illustre non-seulement comment GeoAPI peut-être implémenté, mais aussi comment l’implémentation
peut être testée en utilisant geoapi-conformance
.
Bien que sa mission première soit de servir d’inspiration aux implémenteurs,
geoapi-examples
a tout-de-même été conçu de manière à être utilisable
par des applications ayant des besoins très simples. Tous les exemples étant dans le domaine publique,
les développeurs sont invités à adapter librement des copies de ces classes si nécessaires.
Toutefois si des modifications sont apportées hors du cadre du projet GeoAPI, le bon usage veut que les copies
modifiées soient placées dans un paquet portant un autre nom que org.opengis
.
Pour des besoins un peu plus poussés, les développeurs sont invités à examiner les modules
geoapi-proj4
et geoapi-netcdf
.
Ces deux modules fournissent des exemples d’adaptateurs permettant d’utiliser, via les interfaces de GeoAPI,
une partie des fonctionnalités de bibliothèques externes (Proj.4 et netCDF).
L’avantage de passer par ces interfaces est de disposer d’un modèle unifié pour exploiter deux API très différents,
tout en se gardant la possibilité de basculer plus facilement à une autre bibliothèque si désiré.