content/fr/developer-guide/annexes/geoapi/ReduceDependency.html (176 lines of code) (raw):

<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE html> <!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr"> <head> <title>ReduceDependency</title> <meta charset="UTF-8"/> <link rel="stylesheet" type="text/css" href="../../book.css"/> </head> <body> <!-- Content below this point is copied in "/static/book/fr/developer-guide.html" file by the 'org.apache.sis.internal.book.Assembler' class in 'sis-build-helper' module. --> <section> <header> <h2 id="ReduceDependency">Réduire la dépendance directe envers Apache SIS</h2> </header> <p> 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. </p> <h3 id="UML-annotation-indep">Correspondances entre GeoAPI et les spécifications abstraites</h3> <p> Pour chaque classe, méthode et constante définie à partir d’un standard <abbr>OGC</abbr> ou <abbr>ISO</abbr>, GeoAPI indique sa provenance à l’aide d’annotations définies dans le paquet <code>org.opengis.annotation</code>. Cette correspondante est décrite dans le <a href="#UML-annotation">chapitre à propos de GeoAPI</a>. Les méthodes d’introspections du Java permettent d’accéder à ces informations pendant l’exécution d’une application. La classe <code>org.apache.sis.util.iso.Types</code> fournit des méthodes de commodités telles que <code class="SIS">getStandardName(Class)</code> à cette fin, mais on peut éviter ces méthodes. L’exemple suivant affiche le nom standard de la méthode <code class="GeoAPI">getTitle()</code> de l’interface <code>Citation</code>: </p> <pre><code>Class&lt;?&gt; type = Citation.class; Method method = type.getMethod("<code class="GeoAPI">getTitle</code>", (Class&lt;?&gt;[]) 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);</code></pre> <p> 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 <code class="GeoAPI">class-index.properties</code> fournit dans le paquet <code>org.opengis.annotation</code>. L’exemple suivant lit ce fichier juste avant de rechercher le nom de l’interface correspondant à <code>CI_Citation</code>. Toutefois les utilisateurs sont encouragés à ne lire ce fichier qu’une fois et de conserver son contenu dans une cache de leur application. </p> <pre><code>Properties isoToGeoAPI = new Properties(); try (InputStream in = UML.class.getResourceAsStream("<code class="GeoAPI">class-index.properties</code>")) { isoToGeoAPI.load(in); } String isoName = "<code class="OGC">CI_Citation</code>"; String geoName = isoToGeoAPI.getProperty(isoName); Class&lt;?&gt; type = Class.forName(geoName); System.out.println("L’interface GeoAPI pour le type <abbr>ISO</abbr> " + isoName + " est " + type);</code></pre> <p> La méthode de commodité de <code>org.apache.sis.util.iso.Types</code> correspondante à cette operation est <code class="SIS">forStandardName(String)</code>. </p> <h3 id="ServiceLoader">Obtenir une implémentation des interfaces de GeoAPI</h3> <p> GeoAPI définit des fabriques (<code>Factory</code>) permettant de créer des implémentations de ses interfaces. Par exemple <code>DatumFactory</code> fournit des méthodes permettant de créer des instances implémentant les interfaces du paquet <code>org.opengis.referencing.datum</code>. Ces <code>Factory</code> doivent être implémentées par les bibliothèques géospatiales et déclarées comme <i>services</i> tel que défini par la classe standard <code>java.util.ServiceLoader</code>. La javadoc de <code>ServiceLoader</code> explique la façon de procéder. Mais pour résumer, les bibliothèques doivent créer dans le répertoire <code>META-INF/services/</code> un fichier dont le nom correspond au nom complet de l’interface de la fabrique (<code>org.opengis.referencing.datum.DatumFactory</code> 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. </p> <p> Si la bibliothèque a bien déclaré ses fabriques comme des services, alors les utilisateurs peuvent les obtenir en utilisant <code>ServiceLoader</code> 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. </p> <pre><code>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(…); } }</code></pre> <h4 id="GeoAPI-simple">Fournir sa propre implémentation</h4> <p> 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. </p> <p> 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 <cite>Système de coordonnées</cite> (<abbr>CS</abbr>) et <cite>Système de <u>référence</u> des coordonnées</cite> (<abbr>CRS</abbr>). 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 <code>geoapi-examples</code>, discuté plus loin, fournit de telles combinaisons. Le tableau suivant énumère quelques combinaisons possibles: </p> <table> <tr> <th>Interface principale</th> <th>Interface auxiliaire</th> <th>Usage</th> </tr> <tr> <td><code>CoordinateReferenceSystem</code></td> <td><code>CoordinateSystem</code></td> <td>Description d’un système de référence spatial (<abbr>CRS</abbr>).</td> </tr> <tr> <td><code>GeodeticDatum</code></td> <td><code>Ellipsoid</code></td> <td>Description d’un référentiel geodétique.</td> </tr> <tr> <td><code>CoordinateOperation</code></td> <td><code>MathTransform</code></td> <td>Opération de transformation de coordonnées.</td> </tr> <tr> <td><code>IdentifiedObject</code></td> <td><code>ReferenceIdentifier</code></td> <td>Objet (typiquement un <abbr>CRS</abbr>) que l’on peut identifier par un code.</td> </tr> <tr> <td><code>Citation</code></td> <td><code>InternationalString</code></td> <td>Référence bibliographique composée d’un simple titre.</td> </tr> <tr> <td><code>GeographicBoundingBox</code></td> <td><code>Extent</code></td> <td>Étendue spatiale en degrés de longitude et de latitude.</td> </tr> <tr> <td><code>ParameterValue</code></td> <td><code>ParameterDescriptor</code></td> <td>Description d’un paramètre (nom, type) associée à sa valeur.</td> </tr> <tr> <td><code>ParameterValueGroup</code></td> <td><code>ParameterDescriptorGroup</code></td> <td>Description d’un ensemble de paramètres associés à leurs valeurs.</td> </tr> </table> <p id="GeoAPI-examples"> Le module <code>geoapi-examples</code> 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 <a href="http://www.geoapi.org/geoapi-examples/apidocs/overview-summary.html">Javadoc de ce module</a> é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 <code>geoapi-conformance</code>. </p> <p> Bien que sa mission première soit de servir d’inspiration aux implémenteurs, <code>geoapi-examples</code> 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 <code>org.opengis</code>. </p> <p> Pour des besoins un peu plus poussés, les développeurs sont invités à examiner les modules <code>geoapi-proj4</code> et <code>geoapi-netcdf</code>. 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 <abbr>netCDF</abbr>). L’avantage de passer par ces interfaces est de disposer d’un modèle unifié pour exploiter deux <abbr>API</abbr> très différents, tout en se gardant la possibilité de basculer plus facilement à une autre bibliothèque si désiré. </p> </section> </body> </html>