Developpez.com - Java
X

Choisissez d'abord la catégorieensuite la rubrique :


Présentation de l'API 'Resources'

Par Ioan Calapodescu (home)
 

Ce document présente l'API 'Resources' : objectifs, architecture, détails d'implémentation, exemples et tests. Vous y trouverez aussi des liens et explications pour la javadoc, les sources et les binaires.


1.0. Pour commencer ...
1.1. Objectifs
1.2. Statut
1.3. Ce document
2.0. Pour rentrer dans le vif du sujet ...
2.1. Getting started
2.1.1. Prérequis et téléchargements
2.1.2. Installation et tests
2.1.3. "Hello Resources World"
2.2. Architecture
2.2.1. Vue d'ensemble
2.2.2. Les ressources
2.2.3. Les readers
2.2.4. Les writers
2.2.5. Les autres
3.0. Pour aller plus loin ...
3.1. Téléchargements, liens et docs
3.2. Conclusion


1.0. Pour commencer ...


1.1. Objectifs

Cette API a pour objectif de permettre l'accès à nos ressources (FAQs, pages de codes sources, critiques de livres, etc.) à partir des outils (ie. EDI) utilisés par nos membres.

Les principaux cas d'utilisation de cette API seraient dans des plugins/modules pour Eclipse, Netbeans, etc. ./images/boites/warning-small.png. Voici quelques cas d'utilisation intéressants :

  • Documentation en francais à portée de la main :
    Actuellement, à ma connaissance, aucun EDI ne contient de documentation sur la techno en elle même, mais plutôt sur ses propres fonctionnalités. Et quand c'est le cas, c'est naturellement en anglais et des "cours d'intro" dont on fait vite le tour.
    Avec un de nos plugins : FAQs, codes sources et tutoriels seront directement intégrés dans l'EDI, plus besoin d'ouvrir un navigateur et de faire des "allers-retours".
  • Recherche centralisée :
    Prenons l'exemple du pauvre bougre qui fait du dév. web en Java, et qui pour être à la page fait un peu d'AJAX. Les docs qui l'intéressent se retrouvent disséminés entre la demi-douzaine de FAQs Java, les FAQs CSS, XML, Javascript, les pages de codes sources et les centaines de tutos répartis sur les pages cours des rubriques correspondantes. Bref, même s'il connaît bien dvp, il en a peut-être pour des heures pour retrouver ce qu'il cherche.
    Avec un de nos plugins : il n'aura qu'à "cocher" les ressources qui l'interessent (par exemple la FAQ Java EE, la FAQ XML, la FAQ Javascript, les codes sources Java et les tutos Java) et "taper" AJAX pour obtenir les docs qu'il faut.
    Pour un exemple de recherche multi-ressources voir "Hello Resources World".
  • Nouvelles en direct :
    Prenons l'exemple de la nouvelle page d'accueil de Netbeans 5.5 : elle est sympa, mais je suis prêt à parier qu'elle sera quasiment inutilisée. Pourquoi ? Pour commencer, elle ne contient que des news sur Netbeans, de plus c'est à 90% en anglais. Bref, l'interet ma parait assez limité pour des développeurs Java francophones.
    Par contre, avec cette API, on peut facilement imaginer le même type de page (pour Eclipse et Netbeans) avec des nouvelles en francais, sur l'ensemble des technos Java et plus si affinités (par exemple les news de la rubrique Dév. Web pour les utilisateurs d'Eclipse en tant qu'EDI PHP).
En passant, ca peut aussi nous permettre d'offrir d'autres types de services intéressants. Par exemple, la plupart des EDI actuels proposent des templates/codes clips/snippets, or grâce nos FAQs et codes sources on a de quoi remplir des bouquins entiers de petits morceaux de code réutilisables. On peut très bien imaginer regrouper ce qu'il y a de vraiment réutilisable dans une ressource et rendre le tout accessible grâce aux plugins qu'on aura créés.

Voila, voila, pour les objectifs, passons au statut actuel de "la chose".


1.2. Statut

Pour synthétiser : l'API est écrite, elle est "documentée" (notez les guillemets), un jeu de tests unitaires a été écrit et deux prototypes créés (un module Netbeans et une application Eclipse RCP).

Le module Netbeans

Vous pour voir une démonstration wink de ce module à cete adresse : http://vedaer.developpez.com/netbeans/nbm.htm.

Par contre, disons que j'ai "perdu" les sources. Si ca peut me faire pardonner, et pour la petite histoire, ce n'était que le premier test que j'avais fait pour l'API (depuis, elle a été réecrite pour la mettre au "propre"). De plus, au final, le module, dans l'état ou il était, n'était constitué que de deux ou trois Tree/TableModel et quelques composants SwingX qui se battaient en duel.
Donc, si je peux me permettre, ce n'est pas une très grosse perte.

Au final, il est préférable de repartir de zéro avec la version actuelle de l'API pour faire un joli module Netbeans :)

L'application Eclipse RCP

En dehors des tests unitaires, pour essayer l'API, j'ai écrit une petite application Eclipse RCP que je pense adapter par la suite en plugin pour l'EDI du même nom ./images/boites/info-small.png .

Vous pouvez voir une petite démo (vidéo de 43 Mo !) en cliquant sur la petite image ci contre. La qualité de la vidéo n'est pas tip top, mais je pense pouvoir vous fournir de quoi tester directement très bientôt.

Vous pourrez y voir un exemple de "répertoire de ressources" (FAQs, codes sources, livres, blogs, ...) et quelques fonctionnalités qu'on peut offrir avec cette API : navigation, recherche, contacts des auteurs, bookmarks, ...

Passons à la suite

J'espère que vous voyez maintenant un peu mieux le statut actuel du 'truc' et les possibilités que ca offre. Pour la suite, on ne parlera plus de module, de plugin ou d'EDI, mais simplement de l'API et de son utilisation.
Donc, si vous n'avez pas l'intention de participer au dév. de l'API et des outils cités ci-dessus, la suite aura un peu moins d'interêt puisque ca va se résumer à quelques diagrammes de classe, quelques explications fumeuses et à deux ou trois morceaux de code ;)


1.3. Ce document

Pour commencer, je vais vous guider pour la création d'un "Hello world" (téléchargement, installation, compilation). Ca vous donnera une idée plus claire de ce que j'entends par ressource, répertoire de ressources, etc.

Dans la seconde partie, je vais rentrer un peu dans les détails de l'API : structure, packages, fonctionnalités, exemples divers et tests.

Pour finir, vous trouverez en fin d'article une partie téléchargements : les sources, la javadoc et un exemple de répertoire de ressources pour les tests.


2.0. Pour rentrer dans le vif du sujet ...


2.1. Getting started


2.1.1. Prérequis et téléchargements

Pour pouvoir utiliser/compiler l'API vous devez avoir le JRE/JDK 5.0+ (celui de Sun de préférence : ici).

Vous aurez aussi besoin des sources et du répertoire de ressources exemple.

Pour finir, vous aurez aussi besoin d'un serveur local, au hasard Tomcat. ./images/boites/info-small.png


2.1.2. Installation et tests

Décompressez les archives téléchargées dans le répertoire de votre choix. Elle contiennent deux projets Eclipse. Le premier est l'API (et ses tests), le second est le projet web contenant le répertoire de ressources.

Testons un peu tout ca :

./images/logo-eclipse.png
Eclipse
  • Copiez les deux projets dans votre workspace et importez les : File > Import > Existing Project in Workspace
  • Déployez le projet ResourcesExample à l'adresse http://localhost:8080/ResourcesExample
  • Lancez les tests unitaires. Click droit sur AllTests (projet Resources) > Run > Run as JUnit test
./images/logo-netbeans.png
Netbeans
  • Importez ResourcesExample :
    • File > New project > Web > Web Application with existing sources, sélectionnez ResourcesExample, Next, Finish.
    • Exécutez le projet (F6). Si vous utilisez SAS, il n'y a pas de modifications à faire, par contre si vous utilisez le Tomcat intégré (ou autre chose) regardez le warning ci-dessous.
  • Importez Resources :
    • Supprimez le build.xml dans Resources
    • File > New Project > General > Java project with existing sources, sélectionnez Resources. Nommez le projet Resources.
    • Ajoutez les répertoires src et tests comme répertoires source et test. Finish
    • Ajoutez les jars contenus dans lib au classpath (click droit sur Library > Add Jar/folder)
  • Lancez les tests : click droit sur test.AllTests > Run file
./images/logo-ant.png
Ant
  • Déployez ResourcesExample/ResourcesExample.war. Par exemple, pour tomcat : copiez le fichier dans TOMCAT_HOME/webapps et (re)démarrez
  • Copiez Resources/libs/junit-3.8.1.jar dans ANT_HOME/libs
  • Dans Resources, exécutez : ant build AllTests
./images/boites/warning.png
Adresse de déployement
Si vous ne pouvez pas déployer ResourcesExamples à l'adresse http://localhost:8080/ResourcesExample : remplacez ses occurrences dans les fichiers : repository.xml, listeners-repository.xml et AbstractTest (projet Resources).

Voila, si les tests se sont bien passés, on peut commencer :)

Sinon, ca craint, on vous a dupé, faites une réclamation :( ./images/boites/info-small.png


2.1.3. "Hello Resources World"

Dans ce petit exemple, on va charger un répertoire de ressources, quelques unes des ressources sur lesquelles il pointe et faire une recherche dans celles-ci.

Le répertoire est situé à l'adresse : http://localhost:8080/ResourcesExample/repository.xml. Ce répertoire contient des pointeurs vers diverses ressources. Voici un extrait qui montre les trois ressources que l'on va utiliser pour l'exemple (la FAQ Java SE, la page de codes sources Java et le blog de la rubrique) :
TéléchargerCacher
Fichier repository.xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

<resources:resource xmlns:resources="http://www.developpez.com/resources">
	<id>repJava</id>

    <title>Répertoire de ressources Java</title>
    <!-- ... -->
    <element>
        <id>faqJavaSE</id>

        <title>FAQ Java SE</title>
        <url>http://java.developpez.com/faq/java</url>
        <authors/>
        <contentUrl>http://localhost:8080/ResourcesExample/faq-java.xml</contentUrl>

        <contentReader>com.developpez.resources.readers.FAQReader</contentReader>
    </element>
    <!-- ... -->

    <element>
        <id>sourcesJava</id>
        <title>Codes sources Java</title>
        <url>http://java.developpez.com/sources</url>

        <authors/>
        <contentUrl>http://localhost:8080/ResourcesExample/sources-java.xml</contentUrl>
        <contentReader>com.developpez.resources.readers.FAQReader</contentReader>
    </element>

	<!-- ... -->
    <element>
        <id>blogRubrique</id>
        <title>Blog de la rubrique Java</title>

        <url>http://blog.developpez.com/?blog=42</url>
        <contentUrl>http://blog.developpez.com/xmlsrv/rss2.php?blog=42</contentUrl>
        <contentReader>com.developpez.resources.readers.SyndicationReader</contentReader>

    </element>
    <!-- ... -->
</resources:resource>
Ce qu'il y a d'important de noter c'est que chacun de ces éléments a un identifiant, une URL de contenu et un lecteur de contenu. Par exemple, l'id de la FAQ Java est faqJavaSE, son url de contenu est http://localhost:8080/ResourcesExample/faq-java.xml ./images/boites/info-small.png et son lecteur de contenu est un FAQReader.

Assez de blabla, lisons notre répertoire, chargeons ces trois ressources et faisons une recherche dans celles-ci. Voila notre Hello World :
Cacher
HelloResourcesWorld
  1. import java.util.*; 
  2. import com.developpez.resources.*; 
  3. import com.developpez.resources.search.*; 
  4. public class HelloResourcesWorld { 
  5.     public static void main(String ... args) throws Exception { 
  6.     	// Chargement du répertoire 
  7.         String url = "http://localhost:8080/ResourcesExample/repository.xml"; 
  8.         Resource repository = Resource.getRepository(url); 
  9.          
  10.         // Chargement des ressources 
  11.         Resource faq = repository.getResource("faqJavaSE"); 
  12.         Resource sources = repository.getResource("sourcesJava"); 
  13.         Resource blog = repository.getResource("blogRubrique"); 
  14.          
  15.         // Recherche dans l'ensemble des ressources 
  16.         String query = "xml"; 
  17.         List<SearchResult> search = Search.search(query, faq, sources, blog); 
  18.          
  19.         // Tri et affichage du résultat de la recherche 
  20.         Collections.sort(search, Search.RATE_COMPARATOR); 
  21.         for(SearchResult result : search){ 
  22.             System.out.println(result.getElement().getTitle()); 
  23.         } 
  24.     } 
  25. } 
Qu'est ce qui s'est passé ?

  1. On a chargé le répertoire : celui-ci est en fait une ressource "comme les autres", à la différence que sont reader est fixé (DefaultReader). A partir de l'url passée en paramètre ce dernier charge une instance de Resource : notre répertoire.
  2. On a chargé nos ressources : la méthode getResource(id) commence par chercher dans le répertoire un élément ayant le bon identifiant. Une fois celui-ci trouvé, un reader correspondant à contentReader est instantié et charge une instance de Resource à partir de contentUrl.
  3. on a effectué notre recherche : la classe Search a parcouru l'ensemble des ressources (leurs catégories, sous-catégories, éléments, ...) et a recherché le terme query dans les titres, les descriptions , voir le contenu de tout ce beau monde.
Voila, voila, ... c'est (en gros) pas plus compliqué que ca. Passons aux détails maintenant :)


2.2. Architecture


2.2.1. Vue d'ensemble

Comme vous pouvez le voir ci-contre, la structure de l'API est relativement simple :

  • com.developpez.resources : contient un ensemble d'objets définissant nos ressources, leurs catégories et leur éléments.
  • com.developpez.resources.readers : contient l'interface Reader qui se résume à deux méthodes permettant simplement de récupérer une instance de Resource à patir d'un URL. Ce package contient aussi différentes implémentations de ces lecteurs : des lecteurs de FAQs, de pages sources, de pages livres, de flux RSS, etc.
  • com.developpez.resources.writers : contient l'interface Writer dont vous aurez deviné l'utilité. Les implémentations actuellement présentes nous permettent deux choses : la gestion d'un cache physique de ressources et la transformation de certaines ressources (par exemple une FAQ en flux RSS, Atom, etc.).
  • com.developpez.resources.search : contient une classe utilitaire permettant d'effectuer ddes recherches et une représentation de résultat de recherche (l'élément correspondant, une note, etc.).
  • com.developpez.resources.listeners : contient "le" listener de l'API. A part le fait qu'il doit se sentir très seul, la seule chose qu'on peut remarquer est sa fonctionnalité qui est de nous informer de la présence de nouveaux éléments dans les ressources (par exemple quand un flux RSS ou une FAQ est mise à jour, manuellement ou automatiquement, selon les circonstances).
  • com.developpez.resources.listeners : contient ResourceException. Vous connaissez SQLException ? Eh ben, c'est pareil : une bonne grosse classe pour encapsuler les problèmes que l'on peut rencontrer lors de la lecture d'une ressource (url de contenu inexistante ou innaccessible, flux xml mal formés, ...) ou de son écriture.
Commencons par regarder nos ressources (Resource, Category et Element) de plus près.


2.2.2. Les ressources

Cliquez pour agrandir
Pour schématiser, l'API représente simplement une arborescence de : Resource, Category et Element.

Pour faire le parallèle avec l'API DOM ou tout est Node, dans notre cas tout est Element : on va donc commencer par faire le tour des éléments de ressources, puis des catégories de ressources, puis des ressources et pour finir des répertoires de ressources.

Vous pouvez vous faire une idée en regardant le schéma ci-contre ou encore en regardant la javadoc (en fin d'article).

Elements

Selon le contexte, un élément peut représenter une QR dans une FAQ, une entrée d'un flux RSS où comme on l'a déjà vu un "pointeur" vers une ressource. Ses attributs principaux sont un titre, une description, un contenu, une url, des dates de publication et mise à jour, et un ensemble d'auteurs (nom, éventuellement email et url). Les autres attributs concernent plutôt les "pointeurs de ressources" : une url de contenu, un lecteur de contenu et un délai de mis à jour.

Comme vous pouvez le voir, ca casse pas trois pattes à un canard, mais ca nous permet de modéliser un ensemble de ressources très disparate. En fait, j'aurais bien repris des API comme DOM ou Rome pour ne pas réinventer la roue, mais l'une est "trop complexe" pour nos besoins et l'autre ne permet pas de gérer facilement les catégories de manière arborescente.

Catégories

Une catégorie est simplement un Element contenant d'autres catégories et des éléments. En plus des méthodes d'accès à ces attributs, cette classe contient quelques méthodes utilitaires permettant de rechercher des sous-catégories ou des sous-éléments, de dénombrer le nombre de nouveaux éléments, etc.

Ressources

Une ressource est une catégorie qui dispose de quelques méthodes utilitaires permettant de charger certains de ses éléments (de type "pointeur de ressource", si si souvenez vous les éléments avec des contentUrl, contentReader, updateInterval ;).
Cette classe maintient aussi un cache mémoire des éventuelles ressources chargées à partir de ses "pointeurs".

Répertoire

Ne cherchez pas de classe Repository : un répertoire de ressources est simplement une ressource dont le reader est de type (DefaultReader) et dont l'ensemble des éléments sont de type "pointeur de ressources".

Et je crois bien que c'est tout, mais ca me parait suffisant pour le moment ... :)
Passons aux lecteurs de ressources et voyons quelles sont les ressources actuellement "lisibles" par notre API.


2.2.3. Les readers

Cliquez pour agrandir
Vous pouvez voir ci-contre la structure des lecteurs disponibles actuellement.

  • Reader : une classe abstraite que se doit d'implementer tout lecter digne de ce nom. Elle définit deux méthodes qui permettent simplement de retourner une instance de Resource à partir d'une url (avec éventuellement un marqueur booléen permettant d'indiquer si la ressource doit être rechargée où lue depuis le cache physique).
  • DefaultReader : cette implémentation est basée sur JAXB 2.0. Elle permet de charger des ressources au format XML (celui d'un répertoire de ressources).
  • SyndicationReader : cette implémentation est capable de lire des flux XML de syndication (au moins RSS 1.0, RSS 2.0, Atom 1.0 de manière convenable) grâce à Rome. Elle étend aussi Default reader. En fait elle charge le flux grâce à Rome, le transforme en instance Resource, le met en cache physique et ce sont les méthodes de DefaultReader qui lisent ce cache.
  • TrAXReader : cette implémentation effectue une transformation XSLT sur un fichier XML pour le transformer en fichier lisible par un DefaultReader. Cette classe est abstraite, des implementations existent pour nos FAQs, codes sources et livres (cf. fichier du kit).
  • FAQReader : cette implémentation étend TrAXReader et est capable de transformer FAQs et pags decodes sources.
  • BooksReader : même chose que FAQReader, mais pour les livres ;) J'ai vu que vous avez changé le format des pages livres dernièremnt, la feuille XSL correspondante devra sûrement être modifiée.
Ces premières implémentations nous permettent déjà de lire pas mal de types de ressources, mais, au pire, on peut encore en créer facilement si le besoin s'en fait sentir :)


2.2.4. Les writers

Cliquez pour agrandir
Avant de voir l'ensemble des tests unitaires créés pour l'occasion, faisons un tour de la contrepartie des readers : les writers.

Comme je l'ai dit un peu plus haut, ces writers ont pour le moment deux utilités.

Pour commencer, ce sont les outils utilisés pour le cache physique. Ce cache nous est indispensable, car il nous permet d'avoir accès aux ressources en "mode déconnecté" et d'avoir un accès rapide à ces données. En effet, la lecture d'une FAQ comme la FAQ java (qui dépasse les 10.000 lignes), sa transformation XSLT et sa lecture par JAXB ca peut être assez long. Quand je dis assez long, il faut relativiser (pour l'exemple donné, ca me donne en général : Full load ~ 2000ms, Disk load ~ 200ms, Memory load ~ 2ms). Enfin bref, pour de grosses ressources, qui plus est ne sont pas mise à jour tous les lundi, l'utilisation de ces caches me parrait utile.

La seconde utilité de ces writers est de nous permettre de transformer certaines de nos ressources en flux de syndication. Par exemple, en attendant que ce soit intégré au Kit, on peut avoir des flux RSS pour nos FAQs, pages codes sources et pages livres.

Passons maintenant aux tests unitaires. Si le HelloWorld vous a laissé sur votre faim (et que vous ne vous êtes pas encore endormi;) vous trouverez pas mal d'exemples d'utilisation ci dessous.


2.2.5. Les autres

Cliquez pour agrandir
Pour chacun de ces tests, l'integralité des caches sont vidés. ca permet aussi de se faire une idée des performances de la "bête". Sur ma machine l'ensemble des tests tournent en général en une vingtaine de secondes (sachant que le dernier en prend au moins une dizaine, sachant que c'est un thread qui tourne en attendant que la FAQ java se mette à jour au moins 5 fois, ce qu'elle fait toutes les secondes environ).

  • SimpleTest : voir HelloWorld ;)
  • CacheTest : ce test consiste simplement à tester "l'éfficacité" des caches, histoire de vérifier que le chargement des ressources est de plus en plus rapide selon les caches.
  • ReadersTest : ce test va vérifier l'ensemble des readers disponibles actuellement, c'est à dire Default, FAQs, codes sources, RSS, Atom, Livres (il parcours simplement l'ensemble des ressources du répertoire de test, car il contient un peu de tout).
  • WritersTest : test de la création de flux RSS/Atom à partir du répertoire de ressources et des FAQs (il faudrait aussi l'étendre aux autres types de ressources, passer le tout au validateur et tester dans quelques lecteurs de flux).
  • SearchTest : exemples de recherche, dans une ou plusieurs ressources ou catégories de ressources.
  • ListenersTest : test de la mise à jour des ressources (manuelle ou auto)
Voila pour les tests, c'est tout ce que nous avons pour le moment. D'autres choses sont à écrire/tester comme par exemple la synchronization de l'accès aux ressources ou au fichiers cache, le comportement en face de "mauvaises ressources", de ressources indisponibles, etc. Mais avant de peaufiner tout ca, il faut voir ce que vous pensez de tout ca, si ca vous intéresse, qui voudrait participer, tester, donner son avis sur le fait que le code est écrit dans un abominable franglais, etc.


3.0. Pour aller plus loin ...


3.1. Téléchargements, liens et docs


3.2. Conclusion

Voila, voila, toute remarque, commentaire, avis, conseil est le bienvenu. Et puis, si ca vous intéresse de continuer à bosser la dessus, surtout n'hésitez pas : tout le monde est le bienvenu :)



./images/boites/warning-small.png
Pensons aux autres
Cette API est construite sur la plateforme Java, ce n'est pas pour autant qu'elle va être réservée à la rubrique Java.

En effet, des outils comme Eclipse et Netbeans ne servent pas qu'au développement Java. Ils conviennent aussi parfaitement au développements : PHP, Ruby, Python, Perl, C/C++, ...

Sans parler du fait que des rubriques comme SGBD (MySQL, Oracle, ...), Développement Web (HTML, CSS, Javascript), XML proposent des ressources utiles à de nombreux langages/plateformes de développement.

./images/boites/info-small.png
Le plugin Eclipse
Une fois qu'on aura eu l'occasion de discuter de tout ca, je pense que je vais m'attaquer à la création du plugin pour Eclipse.

Entre la "finalisation" de l'API et ce plugin, je ne pense pas avoir le temps de m'occuper, en plus, d'un module pour Netbeans. Il serait donc intéressant qu'on puisse monter plusieurs équipes pour créer tout ce dont a besoin.
Des volontaires ? :)

./images/boites/info-small.png
Pourquoi un serveur ?
C'est juste pour faire tourner le répertoire de ressources utilisé pour les tests (la description du répertoire, des faqs, des flux choisis, ...).

L'avoir en local permet juste de ne pas dépendre d'une connexion web pour le développement. Ca a aussi l'avantage de rendre les tests unitaires distribuables sans avoir à "polluer" je ne sais quel serveur avec les fichiers utilisés par les tests.

./images/boites/info-small.png
Réclamations
Contactez moi et décrivez moi le problème ;)

./images/boites/info-small.png
Contenu
Pour cette FAQ l'url de contenu est simplement le fichier xml qu'on utilise avec le kit.


Valid XHTML 1.1!Valid CSS!

Responsables bénévoles de la rubrique Java : Mickael Baron - Robin56 -