Android pour les développeurs J2EE

Un modèle asynchrone pour les clients web


précédentsommairesuivant

V. AVAT- Exemple 2

V-A. Le projet

Nous nous proposons de créer une application Android faisant la même chose que précédemment mais dans une architecture client / serveur . Le client sera le suivant :

Image non disponible

C'est le serveur qui génèrera les nombres aléatoires affichés par la tablette Android :

Image non disponible

La couche [métier] aura une méthode de génération de nombres aléatoires exposée au monde web via un service REST.

La couche AVAT du client va rester celle que l'on vient de décrire. Les tâches asynchrones vont bouger un peu : elles exécutent maintenant une méthode de la couche [métier] du client. Nous allons décrire l'application dans l'ordre suivant :

Le serveur

  • sa couche [métier] ;
  • son service REST ;

Le client

  • sa couche [DAO] ;
  • sa couche [métier] ;
  • sa tâche asynchrone.

Le reste ne change pas.

V-B. Le manifeste de l'application Android

Le fichier [AndroidManifest.xml] du projet est un peu différent de celui du projet précédent :

 
CacherSélectionnez

La ligne important est la ligne 11. C'est elle qui permet au client Android d'ouvrir des connexions réseau. Si on l'oublie, ça ne marche pas mais les messages d'erreur ne sont pas toujours explicites quant à la cause de l'erreur.

V-C. Le serveur

V-C-1. La couche [métier]

C'est elle qui génère les nombres aléatoires.

Image non disponible

V-C-1-a. Le projet Eclipse

Le projet Eclipse de la couche [métier] est le suivant :

Image non disponible
  • en [1], le projet est un projet [Maven] ;
  • en [2] :
  • [IMetier] est l'interface de la couche [métier] ;
  • [Metier] l'implémentation de cette interface ;
  • [ServerException] une classe d'exception.

V-C-1-b. Les dépendances Maven

Le fichier [pom.xml] est le suivant :

 
CacherSélectionnez

Il n'y a aucune dépendance.

V-C-1-c. L'interface [IMetier]

Le code de l'interface est le suivant :

 
CacherSélectionnez
  • ligne 6 : la méthode qui génère un nombre aléatoire entre [a,b]

V-C-1-d. L'implémentation [Metier]

Le code de la classe [Metier] est le suivant :

 
CacherSélectionnez

On y trouve ce qui précédemment était dans la tâche [Task_01]. Nous ne commentons pas la classe : elle rend 2 fois sur 3 un nombre aléatoire et 1 fois sur 3 lance une exception.

V-C-1-e. La classe d'exception

La classe d'exception est la suivante :

 
CacherSélectionnez
  • ligne 5 : comme la classe [ClientException] chez le client, la classe [ServerException] dérive de la classe [RuntimeException].

V-C-2. Le service REST

Image non disponible

Le service REST est implémenté par SpringMVC. Un service REST (RepresEntational State Transfer) est un service HTTP répondant aux demandes GET, POST, PUT, DELETE d'un client HTTP. Sa définition formelle indique pour chacune de ces méthodes, les objets que le client doit envoyer et celui qu'il reçoit. Dans les exemples de ce document, nous n'utilisons que la méthode GET alors que dans certains cas, la définition formelle de REST indique qu'on devrait utiliser une méthode PUT. Nous appelons REST notre service parce qu'il est implémenté par un service de Spring qu'on a l'habitude d'appeler service REST et non parce qu'il respecte la définition formelle des services REST.

V-C-2-a. Le projet Eclipse

Le projet Eclipse de la couche [web] est le suivant :

Image non disponible
  • en [1], le projet dans son ensemble ;
  • en [2], les dépendances Maven ;
  • en [3], le projet ne contient qu'une classe.

V-C-2-b. Les dépendances Maven

Le fichier [pom.xml] du projet Maven est le suivant :

 
CacherSélectionnez
  • le service REST est implémenté à l'aide du framework SpringMVC. On trouve donc un certain nombre de dépendances sur ce framework (lignes 29-48) ;
  • lignes 49-53 : le serveur REST va échanger avec ses clients des objets au format JSON (JavaScript Object Notation). C'est une représentation texte des objets. Un objet JAVA peut être sérialisé en un texte JSON. Inversement, ce dernier peut être désérialisé pour créer un objet JAVA. Côté serveur, la bibliothèque Jackson est utilisée pour faire ces opérations ;
  • lignes 54-58 : le serveur REST a une dépendance sur la couche [métier] que nous avons décrite.

V-C-2-c. Configuration du service REST

Un service REST est une application web et à ce titre est configurée par un fichier [web.xml] classique :

Image non disponible

est le suivant :

 
CacherSélectionnez
  • lignes 4-12 : définition d'une servlet, une classe capable de traiter les requêtes HTTP des clients web ;
  • ligne 5 : son nom restservices. On peut l'appeler comme on veut ;
  • ligne 6 : la servlet qui gère les requêtes HTTP des clients web. C'est la classe [DispatcherServlet] de SpringMVC ;
  • lignes 7-10 : indiquent le fichier de configuration de la servlet, ici [WEB-INF/rest-services-config.xml] ;
  • ligne 11 : la servlet sera chargée au démarrage du serveur, ici un serveur Tomcat 7 ;
  • lignes 13-16 : les URL (ligne 15) traitées par la servlet restservices (ligne 14).

Au final, ce fichier indique que toutes les URL (ligne 15) seront gérées par la servlet restservices (ligne 14) définie lignes 4-12.

V-C-2-d. SpringMVC

SpringMVC est un framework MVC (Modèle-Vue-Contrôleur). Rappelons les grands principes de ce design pattern :

Image non disponible

Le traitement d'une demande d'un client se déroule selon les étapes suivantes :

  • le client fait une demande au contrôleur. Celui-ci voit passer toutes les demandes des clients. C'est la porte d'entrée de l'application. C'est le C de MVC.
  • le contrôleur C traite cette demande. Pour ce faire, il peut avoir besoin de l'aide de la couche métier. Une fois la demande du client traitée, celle-ci peut appeler diverses réponses. Un exemple classique est :
  • le contrôleur choisit la réponse (= vue) à envoyer au client. Choisir la réponse à envoyer au client nécessite plusieurs étapes :

L'étape 3 consiste donc en le choix d'une vue V et en la construction du modèle M nécessaire à celle-ci.

  • le contrôleur C demande à la vue choisie de s'afficher.
  • la vue V utilise le modèle M préparé par le contrôleur C pour initialiser les parties dynamiques de la réponse qu'elle doit envoyer au client.
  • la réponse est envoyée au client. Ce peut être un flux HTML, PDF, Excel…

Spring MVC implémente cette architecture de la façon suivante :

Image non disponible
  • le client fait une demande au contrôleur. Celui-ci voit passer toutes les demandes des clients. C'est la porte d'entrée de l'application. C'est le C de MVC. Ici le contrôleur est assuré par une servlet générique :
    org.springframework.web.servlet.DispatcherServlet
  • le contrôleur principal [DispatcherServlet] fait exécuter l'action demandée par l'utilisateur par une classe implémentant l'interface :
    org.springframework.web.servlet.mvc.Controller
    A cause du nom de l'interface, nous appellerons une telle classe un contrôleur secondaire pour le distinguer du contrôleur principal [DispatcherServlet] ou simplement contrôleur lorsqu'il n'y a pas d'ambiguïté. Le schéma ci-dessus s'est contenté de représenter un contrôleur particulier. Il y a en général plusieurs contrôleurs, un par action.
  • le contrôleur [Controller] traite une demande particulière de l'utilisateur. Pour ce faire, il peut avoir besoin de l'aide de la couche métier. Une fois la demande du client traitée, celle-ci peut appeler diverses réponses. Un exemple classique est :
  • le contrôleur choisit la réponse (= vue) à envoyer au client. Choisir la réponse à envoyer au client nécessite plusieurs étapes :

L'étape 4 consiste donc en le choix d'une vue V et la construction du modèle M nécessaire à celle-ci.

  • le contrôleur DispatcherServlet demande à la vue choisie de s'afficher. Il s'agit d'une classe implémentant l'interface

org.springframework.web.servlet.View

Spring MVC propose différentes implémentations de cette interface pour générer des flux HTML, Excel, PDF… Le schéma ci-dessus s'est contenté de représenter une vue particulière. Il y a en général plusieurs vues.

  • le générateur de vue View utilise le modèle Map préparé par le contrôleur Controller pour initialiser les parties dynamiques de la réponse qu'il doit envoyer au client.
  • la réponse est envoyée au client. La forme exacte de celle-ci dépend du générateur de vue. Ce peut être un flux HTML, PDF, Excel…

Dans notre cas, la classe [DispatcherServlet] est configurée par le fichier [] suivant :

 
CacherSélectionnez
  • ligne 13 : le bean de la couche [métier]. Il sera instancié par Spring ;
  • ligne 16 : il est possible de configurer Spring à l'aide d'annotations dans le code Java. C'est ce qui a été fait ici. La ligne 16 dit à Spring d'exploiter les annotations qu'il trouvera dans le package [istia.st.avat.server] ;

Il y trouvera trois genres d'annotations :

 
CacherSélectionnez
  • ligne 1 : l'annotation @Controller fait de la classe [RestMetier] un contrôleur SpringMVC, c-à-d une classe capable de traiter des requêtes HTTP. Celles-ci sont définies par l'annotation @RequestMapping qu'on voit en ligne 11 ;
  • lignes 5 et 7 : l'annotation @Autowired tague des champs qui sont des références sur des beans définis dans le fichier de configuration de SpringMVC. Dans notre cas, ce sont les beans des lignes 2 et 8 du fichier [rest-services-config.xml] ci-dessous. Les champs des lignes ainsi taguées sont automatiquement initialisés par Spring.

Revenons au code du fichier [rest-services-config.xml] :

 
CacherSélectionnez
  • lignes 8-10 : les vues générées par l'unique contrôleur seront du type [MappingJacksonJsonView] (ligne 9). Cette vue va transformer son modèle en un unique objet JSON qu'elle va transmettre à son client. La ligne 10 configure un entête HTTP envoyé par le serveur à son client : elle dit que le serveur envoie du texte, ici l'objet JSON ;
  • lignes 14-16 : un « convertisseur de messages ». Je ne sais pas bien ce que signifie cette expression. Il semble que cela définisse une classe capable de créer un objet à partir d'une requête ou d'une réponse HTTP et inversement. Ici la classe [MappingJacksonHttpMessageConverter] va créer un objet JSON à partir du modèle de la vue. Inversement, elle est capable de produire un objet Java à partir de données JSON postées par le client ;
  • lignes 18-25 : il peut y avoir plusieurs « convertisseurs de messages » pour différents cas de figure. Entre les lignes 21-23, on met les beans chargés de « convertir des messages ». On y met donc le bean défini ligne 14. C'est le seul.

V-C-2-e. Le serveur REST

Maintenons que nous avons vu comment le service REST était configuré, examinons son code :

Image non disponible

Le code de la classe [RestMetier] est le suivant :

 
CacherSélectionnez
  • ligne 19 : la méthode qui génère le nombre aléatoire. Lorsqu'elle s'exécute, les champs des lignes 13 et 15 ont été initialisés par SpringMVC. Par ailleurs, si elle s'exécute, c'est parce que le serveur web a reçu une requête HTTP GET pour l'URL de la ligne 18 ;
  • ligne 18 : l'URL traitée est de la forme /random/{a}/{b} où {x} représente une variable. Les deux variables {a} et {b} sont affectées aux paramètres de la méthode lignes 19 et 20. Cela se fait via l'annotation @PathVariable(" x "). On notera que {a} et {b} sont des composantes d'une URL et sont donc de type String. La conversion de String vers le type des paramètres peut échouer. SpringMVC lance alors une exception. Résumons : si avec un navigateur je demande l'URL /random/100/200, la méthode random de la ligne 19 s'exécutera avec les paramètres entiers 100 et 200 ;
  • ligne 25 : on demande à la couche [métier] un nombre aléatoire dans l'intervalle [a,b]. On se souvient que la méthode [metier].random peut lancer des exceptions. On les gère ;
  • ligne 27 : le contrôleur MVC rend une vue (View) avec son modèle (Map). Ici la View sera celle de la ligne 15, une JacksonView définie dans le fichier de configuration de Spring, donc une vue qui transforme son modèle en objet JSON. Le modèle ici sera un dictionnaire (Map) avec la clé " data " et la valeur associée le nombre aléatoire, par exemple " 140 ". La chaîne JSON correspondant à ce modèle est la suivante :
 
CacherSélectionnez

C'est donc cette chaîne que recevra le client.

  • lignes 35-39 : la vue envoyée lorsque se produit une exception ;
  • lignes 36-38 : on construit un dictionnaire avec deux clés :
  • "error" : un n° d'erreur. Ici ce sera 103,
  • "message" : le message de l'erreur ;

La chaîne JSON envoyée au client aura la forme

 
CacherSélectionnez

Ceux qui ne connaissent pas le format JSON trouveront page , paragraphe , un exemple de lecture / écriture de JSON avec la bibliothèque Jackson.

V-C-2-f. Déploiement et test du service REST

Image non disponible
  • en [1, 2] : le service REST est exécuté sur le serveur Tomcat ;Image non disponible
  • en [3], le fichier [index.jsp] de l'application web a été exécuté ;
  • en [4], on demande l'URL du service de génération du nombre aléatoire. Ici, on demande un nombre entre 100 et 200 ;
  • en [5], la réponse JSON ;Image non disponible
  • en [6] : en rafraîchissant la page un certain nombre de fois, on récupère l'exception aléatoire générée par la couche [métier], de nouveau au format JSON.

V-D. Le client Android

Le client Android a l'architecture suivante :

Image non disponible

Le client a trois composantes :

  • la couche [AVAT] que nous avons étudiée dans l'exemple précédent ;
  • la couche [métier] qui va présenter une interface analogue à celle de la couche [métier] du serveur ;
  • la couche [DAO] qui s'adresse au service REST que nous avons étudié précédemment.

V-D-1. La couche [metier]

V-D-1-a. Le projet Eclipse

Le projet Eclipse est le suivant :

Image non disponible
  • en [1], le projet Eclipse de la couche [métier] ;
  • en [2], les dépendances Maven du projet ;
  • en [3], l'implémentation de la couche [métier] ;

V-D-1-b. Les dépendances Maven

Le fichier [pom.xml] du projet Maven est le suivant :

 
CacherSélectionnez

Le projet de la couche [métier] a une unique dépendance (lignes 12-15) sur la couche [DAO] que nous n'avons pas encore écrite.

V-D-1-c. Implémentation de la couche [métier]

Image non disponible

Rappelons l'interface de la couche [métier] du serveur :

 
CacherSélectionnez

Celle du client sera analogue :

 
CacherSélectionnez
  • ligne 8 : la méthode de génération du nombre aléatoire. Un nouveau paramètre s'ajoute : celle de l'URL du service REST qui délivre ce nombre ;
  • ligne 10 : la couche [métier] a besoin de la couche [DAO]. C'est cette dernière qui assure les échanges avec le service REST.

L'implémentation [Metier] du client est la suivante :

 
CacherSélectionnez
  • lignes 3-4 : la couche [métier] s'appuie sur la couche [DAO] ;
  • ligne 9 : elle utilise une bibliothèque JSON de Google appelée Gson. Ceci nous est imposé par la bibliothèque utilisée [spring-android-rest-template]. Cette bibliothèque de Spring va s'interfacer avec le serveur REST SpringMVC. On trouvera page , paragraphe , un exemple de lecture / écriture de JSON avec la bibliothèque Gson ;
  • ligne 14 : une référence sur la couche [DAO]. Elle sera instanciée par la fabrique d'objets du modèle AVAT ;
  • ligne 16 : l'objet Gson qui va nous permettre de sérialiser / désérialiser des objets JSON ;
  • ligne 19 : la méthode de génération du nombre aléatoire. Le 1er paramètre est l'adresse du service REST, les deux autres les bornes de l'intervalle [a,b] dans lequel on tire le nombre aléatoire ;
  • ligne 21 : on construit l'URL complète du service REST demandé. On notera bien la syntaxe des variables a et b dans l'URL ;
  • lignes 23-25 : un dictionnaire dont les clés sont les variables de l'URL demandée ;
  • ligne 27 : on exécute la méthode [dao].executeRestService de la couche [DAO] avec les paramètres suivants :
  • la méthode " get " ou " post " de la requête HTTP à émettre,
  • l'URL complète du service REST à exécuter,
  • un dictionnaire des données transmises par une opération HTTP POST. Donc null ici, puisqu'on fait une opération HTTP GET,
  • sous la forme d'un dictionnaire, les valeurs des variables de l'URL, ici les variables {a} et {b} ;

On ne gère pas d'exception. On verra prochainement que la couche [DAO] lance des exceptions non contrôlées. Elles vont remonter toutes seules jusqu'à la couche [Présentation] assurée par le modèle AVAT ;

  • lignes 29-33 : on a reçu une chaîne JSON du serveur. On attend un entier aléatoire dans l'intervalle [a,b]. On essaie donc de transformer la chaîne en entier. Si on y arrive, on rend ce nombre (ligne 30) comme résultat de la méthode sinon on lance une exception (ligne 32).

V-D-2. La couche [DAO]

Image non disponible

V-D-2-a. Le projet Eclipse

Le projet Eclipse est le suivant :

Image non disponible
  • en [1], le projet Eclipse de la couche [DAO] ;
  • en [2], les dépendances Maven du projet ;
  • en [3], l'implémentation de la couche [DAO] ;

V-D-2-b. Les dépendances Maven

Le fichier [pom.xml] du projet Maven est le suivant :

 
CacherSélectionnez

Le projet de la couche [DAO] a deux dépendances :

  • la communication avec le serveur REST va être assurée par un client REST fourni par la bibliothèque [spring-android-rest-template] (lignes 23-27) ;
  • l'échange d'objets JSON entre le client et le serveur REST nous oblige à avoir une bibliothèque de sérialisation / désérialisation d'objets JSON. Ce sera la bibliothèque Gson de Google (lignes 29-33).

V-D-2-c. Implémentation de la couche [DAO]

Image non disponible

L'interface de la couche [DAO] est la suivante :

 
CacherSélectionnez
  • ligne 6 : la méthode [executeRestService] dont nous avons parlé précédemment ;
  • ligne 8 : une méthode pour fixer un temps de réponse maximal de la part du serveur REST. Passé ce délai, la couche [DAO] lance une exception [ClientException]. Ce temp est fixé en millisecondes.

L'implémentation est la suivante :

 
CacherSélectionnez
  • lignes 5-7 : la couche [DAO] s'appuie sur un client REST fourni par la bibliothèque [spring-android-framework]. Le principal élément de cette bibliothèque est la classe [RestTemplate] de la ligne 7. Le cœur du framework Spring n'a pas encore été porté sur Android. Alors qu'habituellement, le champ de la ligne 7 aurait été initialisé par Spring, ici il le sera par le constructeur ;
  • ligne 21 : l'objet [RestTemplate] est instancié ;
  • lignes 23-24 : il est configuré. On lui donne ici à la main la liste de " convertisseurs de message " qu'on avait définie dans le fichier de configuration du serveur REST. Dans ce dernier, on n'avait défini que le convertisseur [JacksonHttpMessageConverter]. Ici pour le remplacer on utilise le convertisseur [GsonHttpMessageConverter] qui utilise la bibliothèque Gson. On définit également le convertisseur [StringHttpMessageConverter]. On n'en avait pas eu besoin pour le serveur. Ici, le client plante sans ce convertisseur ;
  • ligne 28 : la méthode [executeRestService] reçoit les paramètres suivants :
  • ligne 32 : on vérifie que le serveur REST répond au bout de timeout millisecondes. Si ce n'est pas le cas, la méthode [checkResponsiveness] lance une exception ;
  • lignes 34-37 : vérification de la méthode HTTP ;
  • lignes 38-45 : exécution du service REST par l'objet [RestTemplate] de Spring (ligne 12). Cette classe a de nombreuses méthodes pour dialoguer avec un service REST. Celles utilisées ici vont rendre comme résultat, la chaîne JSON renvoyée par le serveur. On se rappelle que celui-ci peut renvoyer deux types de chaînes JSON :
  • la méthode " get " ou " post " de la requête HTTP à émettre,
  • l'URL complète du service REST à exécuter,
  • un dictionnaire des données transmises par une opération HTTP POST ;
  • sous la forme d'un dictionnaire, les valeurs des variables de l'URL ;
 
CacherSélectionnez

Ligne 1, la chaîne contenant le nombre aléatoire, ligne 2, la chaîne contenant un message d'erreur.

  • ligne 47 : on transforme la chaîne JSON reçue en dictionnaire ;
  • ligne 50 : on regarde si dans ce dictionnaire il y a la clé "error". Si oui, on lance une [ClientException] (lignes 51-54) ;
  • ligne 56-59 : on regarde si dans ce dictionnaire il y a la clé "data". Si non, on lance une [ClientException] (lignes 57-59) ;
  • ligne 61 : on retourne le nombre aléatoire.

La méthode [checkResponsiveness] est la suivante :

 
CacherSélectionnez
  • ligne 1 : le paramètre [urlService] est de la forme [http://localhost:8080/server-rest/random/{a}/{b}];
  • ligne 3 : l'URL précédente devient [http://localhost:8080/server-rest/random/a/b];
  • lignes 5-9 : à partir de cette URL, on essaie de construire un objet URI. Si on n'y arrive pas c'est que l'URL est incorrecte ;
  • lignes 14-15 : on se connecte à la machine et au port définis par l'URI qui vient d'être construite et on donne un temps maximum de timeout millisecondes pour obtenir la réponse (ligne 15) ;
  • ligne 18 : si pour une raison ou une autre (absence du serveur ou délai d'attente dépassé), la connexion échoue alors on lance une exception.

V-D-3. La couche [AVAT]

Image non disponible

La couche [AVAT] change peu vis à vis de la version précédente :

  • la vue demande une information supplémentaire, l'URL du service REST ;
  • la tâche asynchrone [Task_01] évolue.

V-D-3-a. Le projet Eclipse

Image non disponible
  • en [1], le projet Eclipse de la couche [AVAT] ;
  • en [2], les dépendances Maven du projet ;
  • en [3], l'implémentation de la couche [AVAT] ;

V-D-3-b. Les dépendances Maven

Le fichier [pom.xml] du projet est le suivant :

 
CacherSélectionnez
  • lignes 18-23 : dépendance sur la plateforme Android ;
  • lignes 24-29 : dépendance sur le modèle [AVAT] ;
  • lignes 30-34 : dépendance sur la couche [métier] du client ;

V-D-3-c. La tâche [Task_01]

Image non disponible

La classe [Task_01] devient la suivante :

 
CacherSélectionnez
  • ligne 17 : dans la version précédente, la méthode [doWork] recevait trois paramètres. Elle en reçoit maintenant un de plus : l'URL du service REST qui délivre les nombres aléatoires ;
  • ligne 51 : le nombre aléatoire est délivré par la couche [métier] du client. La tâche demande à la fabrique d'objets une référence sur cette couche. Celle-ci est un singleton. La fabrique ne la crée qu'en un unique exemplaire ;
  • ligne 53 : le nombre aléatoire est demandé à la couche [métier].

V-D-3-d. La vue [Vue_01]

Image non disponible

La vue [Vue_01] évolue pour demander une information supplémentaire : l'URL du service REST :

Image non disponible

Pour mettre la bonne URL en [1], on peut procéder ainsi :

  • taper la commande [ipconfig] dans une fenêtre [DOS] :Image non disponible
  • prendre l'adresse IP [2] de la carte Wifi [1] ;
  • déployer le serveur REST sous Eclipse et demander l'URL du service REST avec un navigateur. Utiliser l'adresse IP précédente ; Image non disponible
  • l'URL du service REST à taper sur la tablette est alors [172.16.1.84:080/server-rest]. Il faudra peut-être désactiver le pare-feu du PC voire inhiber un éventuel logiciel antivirus qui pourrait bloquer les connexions entrantes. C'est par exemple le cas de Mcafee.

V-D-3-e. La configuration de l'application

La classe [Config] qui configure l'application est la suivante :

 
CacherSélectionnez

V-D-3-f. La fabrique d'objets

Il y a davantage d'objets dans cette application que dans la précédente. La fabrique d'objets est la suivante :

 
CacherSélectionnez
  • lignes 60-72 : instanciation de la couche [métier] ;
  • ligne 64 : on instancie la couche [DAO] ;
  • ligne 65 : on lui injecte son timeout ;
  • ligne 67 : on instancie la couche [métier] ;
  • ligne 68 : on lui injecte une référence sur la couche [DAO] ;
  • ligne 62 : la couche [métier] est un singleton. Une fois créé, il est recyclé.

précédentsommairesuivant

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2013 Serge Tahé. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.