Mise en place d’un webservice SOAP avec Talend Open Studio : un exemple avec des chats
Sommaire
Talend Open Studio est un outil libre développé en Java de manipulation de données : intégration, ETL, big data, master data, etc. Nous allons l’utiliser ici afin de peupler une base de données de chats que nous requêterons grâce à un webservice SOAP.
Avant de commencer
Nous avons besoin des logiciels suivants :
- La dernière version du Java JDK
- Talend Open Studio for Enterprise Service Bus (TOS for ESB) dans sa version open source pour créer le webservice
- SoapUI dans sa version open source pour tester le webservice
- Une base de données MySQL avec MySQL Workbench ou PhpMyAdmin pour l’administration
Je travaille avec MySQL sous Debian 8 Jessie mais vous pouvez utiliser une autre base de données et/ou un autre système d’exploitation, cela ne posera pas de problèmes.
Ma base de données locale se nomme test, elle possède une table chats dont voici la structure :
CREATE TABLE IF NOT EXISTS `chats` ( `id_chat` int(11) NOT NULL, `nom_chat` varchar(50) NOT NULL, `age_chat` int(11) NOT NULL, `pelage_chat` varchar(30) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1; ALTER TABLE `chats` ADD PRIMARY KEY (`id_chat`);
Le champ id_chat n’est pas en AUTO_INCREMENT et c’est normal, nous utiliserons une séquence numérique au sein de Talend afin de générer des données.
Talend
Le dossier zippé contient deux sous-dossiers :
- Studio : Exécutable de Talend Open Studio
- Runtime_ESBSE : Autres exécutables dont Karaf que nous utiliserons ultérieurement
Talend Open Studio (TOS) est basé sur Eclipse et ça se voit :
Vous êtes prêt ? Allons-y !
Première étape : alimentation de la base
Création des métadonnées
Avant tout chose il faut créer les métadonnées dans Talend. Les métadonnées permettent d’identifier des sources de données (fichiers plats, csv, xml, base de données…) afin de pouvoir les utiliser facilement dans les jobs.
Ajoutons notre table chats :
J’utilise le connecteur MySQL5, mais Talend est développé en Java et possède l’ensemble des connecteurs Java aux différentes bases de données. Dans tous les cas il faudra télécharger les modules supplémentaires avant de vérifier la connexion à la base de données.
Nous sommes connectés. Nous pouvons maintenant récupérer la structure des tables de notre base de données. Talend fonctionne en interne avec des flux xml et utilise des types de données primitifs. Il doit avant toute utilisation de vos données en récupérer la structure.
A la fin de la procédure Talend affiche la structure de chacune des tables.
Nous retrouvons les champs de la table chats.
Alimentation de la base
Nous avons une métadonnée relative à notre table chats. Nous pouvons maintenant créer un job afin de générer des données aléatoires. Nous allons générer des chats !
Les jobs de Talend fonctionnent avec des composants. Ces composants possèdent un flux d’entrée et/ou un flux de sortie. Les flux lient les composants entre eux.
La première chose à faire dans notre nouveau job est d’y insérer un composant tMysqlOutput (écriture dans une table MySQL) qui pointe sur notre table chats. Nous utilisons pour cela notre métadonnée que nous pouvons faire glisser.
Talend nous demande quel composant utiliser : il propose la liste des composants compatibles avec une métadonnée MySQL. Nous choisissons un tMysqlOutput pour écrire dans la table.
Notre composant apparait. Nous pouvons en vérifier la configuration dans l’onglet composant.
Il faut maintenant ajouter un composant qui va générer des données (des chats en l’occurrence). Les deux composants seront liés par un flux. Ajoutez un composant tRowGenerator depuis votre palette à droite.
Liez le composant tRowGenerator au composant tMysqlOuput.
Talend vous demande si il doit récupérer le schéma du composant cible : OUI ! Il va ainsi imposer au composant tRowGenerator la structure de la table chats. Ouvrez l’éditeur pour vérifier.
L’éditeur nous laisse le choix de la fonction à utiliser pour chacun des champs.
Talend propose de nombreuses fonctions de génération de données. La première que nous allons utiliser est Numeric.sequence pour alimenter le champ id_chat afin de simuler l’auto incrémentation du champ.
Notre séquence s’appelle s1, elle commence à 1 et son incrément est également de 1.
Nos chats porterons les prénoms des présidents des États Unis avec la fonction TalendDataGenerator.getFirstName().
L’age des chats sera compris entre 1 et 20 ans avec la fonction Numeric.random().
Pour le pelage de nos félins ce sera un peu plus compliqué : Talend ne propose bizarrement pas de fonction prédéfinie pour ça. Nous pouvons heureusement développer notre propre fonction en java.
Validez le composant tRowGenerator et allez jeter un œil à la classe TalendDataGenerator depuis le panneau de gauche, rubrique Code puis Routines. Nous y retrouvons les méthodes getLastName() et getFirstName().
Je vous propose de créer une nouvelle classe nommée ChatGenerator.
Cette classe implémente une méthode getPelage() dont voici le code largement inspiré de la classe TalendDataGenerator :
public class ChatGenerator { /** * {talendTypes} String * * {Category} ChatGenerator * * {example} getPelage() # Blanc. */ public static String getPelage() { String[] list = { "Blanc", "Noir", "Roux", "Tigré", "Gris", "Brun" }; Integer random = 0 + ((Long) Math.round(Math.random() * (list.length - 1 - 0))).intValue(); return list[random]; } }
Nous pouvons maintenant utiliser notre fonction dans le composant tRowGenerator afin de remplir le champ pelage_chat de notre base de données. Il est possible que le tRowGenerator ne détecte pas directement la nouvelle classe. N’hésitez pas à redémarrer Talend dans ce cas.
Tous nos champs sont renseignés dans le tRowGenerator. Nous pouvons tester le composant avant d’exécuter le job.
C’est tout bon. Il ne nous reste plus qu’à définir le nombre de ligne à écrire dans la table chats avant d’exécuter le job.
L’exécution du job se fait depuis l’onglet Éxecuter.
Tout s’est bien passé, la sortie ne comporte pas d’erreur. Talend nous rapporte aussi la vitesse en lignes par seconde (rows/s) pour chaque flux des jobs.
200 chats en 0.7s, soit 285 chats par seconde… Pas mal !
Vérifions le résultat dans la base de données avant de passer à l’étape suivante :
mysql> SELECT COUNT(*) FROM chats; +----------+ | COUNT(*) | +----------+ | 200 | +----------+ 1 row in set (0.00 sec) mysql> SELECT * FROM chats LIMIT 10; +---------+------------+----------+-------------+ | id_chat | nom_chat | age_chat | pelage_chat | +---------+------------+----------+-------------+ | 1 | Rutherford | 11 | Tigré | | 2 | Lyndon | 4 | Roux | | 3 | Benjamin | 3 | Roux | | 4 | Jimmy | 18 | Noir | | 5 | Ulysses | 11 | Roux | | 6 | Ulysses | 19 | Noir | | 7 | Warren | 8 | Roux | | 8 | William | 5 | Gris | | 9 | Ulysses | 16 | Noir | | 10 | Lyndon | 16 | Gris | +---------+------------+----------+-------------+ 10 rows in set (0.00 sec)
Deuxième étape : création du webservice
Notre webservice SOAP possède une WSDL que nous pouvons créer facilement avec Talend sans toucher une seule ligne de XML. Grossièrement, nos données d’entrées et de sorties seront les suivantes :
Entrée
<nom_chat></nom_chat>
Sortie
<chats> <chat id_chat=""> <nom_chat></nom_chat> <age_chat></age_chat> <pelage_chat></pelage_chat> </chat> </chats>
Il est possible que nous ayons des chats homonymes même si il possèdent un pelage et un age différent. Notre pattern de sortie doit en tenir compte.
De plus, le champ id_chat n’est pas une balise comme les autres champs mais un attribut de sa balise parente.
Création de la WSDL
La création d’un webservice au sein de Talend se fait depuis le panneau de gauche, rubrique Services. Notre webservice s’appellera ChatsWS.
Par défaut Talend créé une opération ChatWSOperation.
Supprimez cette opération afin de créer la notre : getChatsByNom.
Il faut maintenant renseigner les champs de la request (input) et de la response (output). Cliquez sur les flèches à droite.
Pour la request, nous n’avons qu’un seul champ en entrée : nom_chat de type String.
Pour la response c’est un peu plus compliqué. Nous avons un élément racine chats qui contient des éléments chat. Cet élément chat contient nos champs id, nom, age et pelage.
Créez l’élément chats sur la response et affectez lui un nouveau type. Notre nouveau type s’appelle chats.
Afin de renseigner le contenu de notre nouveau type, un dictionnaire de données est accessible depuis l’icône en haut à gauche.
Nous y retrouvons notre nouveau type chats. Cliquez dessus afin de l’éditer.
Notre éléments chats contient un seul élément nommé chat de type chat.
Le résultat est normalement le suivant :
Nous pouvons maintenant ajouter à notre élément chat l’attribut id_chat et les éléments (balises XML) nom_chat, age_chat, et pelage_chat en faisant attention à leurs types respectifs.
Ce qui nous donne à la fin :
Nous avons terminé ici notre WSDL, nous devons maintenant générer le binding content.
Il nous reste une dernière chose à faire : importer les schémas de la WSDL. Cela aura pour effet de créer des métadonnées XML à l’image de la WSDL.
Vérifions :
La prochaine étape est d’utiliser un job afin de lire dans la base de données à l’appel du webservice.
Lecture en base de données
Afin d’assigner un job à l’opération getChatsByNom de notre webservice, faites un clic droit dessus et sélectionnez Assign job.
Un nouveau job sera crée avec deux composants : tESBProviderRequest_1 et tESBProviderResponse_1. Ces composants correspondent à l’entrée et à la sortie de l’opération de notre webservice.
Nous allons maintenant utiliser le composant tXmlMap qui est semblable au composant tMap. Le composant tMap est à mon avis le composant le plus populaire de Talend. Il permet entre autres d’effectuer des jointures entre différentes sources d’entrée et de sortie. Le tXmlMap permet de faire la même chose en mappant des entrées et sorties au format XML, pratique dans le cas des webservices.
Le composant possède une entrée principale : la sortie du tESBProviderRequest (afin de récupérer les paramètres d’entrée du webservice) et une entrée secondaire : une requête dans la table chats avec un tMysqlInput.
Commencez par relier le tESBProviderRequest à un nouveau tXmlMap.
Ouvrez l’éditeur du tXmlMap en double cliquant dessus. Vous constatez sur la colonne de gauche une entrée row1 qui possède une colonne payload. Cette colonne payload correspond à l’entrée XML du webservice. Nous pouvons la mapper très facilement en récupérant la métadonnée XML créée précédemment depuis la WSDL.
Faites un clic doit sur la colonne payload puis import from repository.
Sélectionnez la métadonnée de la request de la WSDL.
Notre colonne nom_chat apparaît ! Nous pouvons l’utiliser !
Nous en avons terminé avec l’entrée principale du tXmlMap. Fermez-le et ajoutez une source de données tMysqlInput depuis la métadonnée chats. Mappez cette source de données en entrée secondaire du tXmlMap.
Rouvrez le tXmlMap et admirez la deuxième entrée row2.
Effectuez une jointure entre les colonnes nom_chat de row1 et row2.
Fermez le composant et créez une nouvelle sortie out1 en récupérant le schéma du composant cible, sinon le payload n’apparaitra pas.
Rouvrez le composant tXmlMap et mappez les champs de la colonne payload de la sortie depuis la métadonnée XML (avec un Import from repository) comme nous l’avons fait pour l’entrée du webservice.
Le champ id_chat n’a pas été récupéré. Je le crée à la main.
Il ne nous reste plus qu’à mapper (encore) les champs des entrées vers les champs de la sortie.
Par défaut, le tXmlMap ne ressortira que le premier résultat, or nous avons plusieurs chats avec le même nom. Il faut donc modifier quelques paramètres.
Du côté de l’entrée row2, cliquez sur la petite clé à molette afin d’afficher les paramètres supplémentaires et choisissez All matches pour le paramètre Match Model.
Du côté de la sortie, affectez la valeur true au paramètre All in one.
Définissez le chat de la sortie comme élément de boucle (as loop element).
Nous en avons terminé avec le tXmlMap. Lancez l’exécution du job.
L’outil nous donne gentiment l’adresse du endpoint : http://localhost:8090/services/ChatsWS afin que nous puissions tester avec SoapUI.
Créez un nouveau projet de type soap avec SoapUI et donnez-lui l’adresse de la WSDL. N’oubliez pas de rajouter ?wsdl à la fin de l’adresse du endpoint.
SoapUI liste ensuite l’ensemble des opérations de notre webservice comme ceci. Nous retrouvons getChatsByNom.
Si nous ouvrons Request1 de l’opération getChatsByNom, nous reconnaissons notre flux d’entrée avec le paramètre nom_chat :
Un petit test avec John.
Miracle ! Nous retrouvons nos chats ! Toutes les variables sont bonnes. Vous pouvez vérifier de votre côté dans la base de données.
mysql> SELECT * FROM chats WHERE nom_chat LIKE 'John'; +---------+----------+----------+-------------+ | id_chat | nom_chat | age_chat | pelage_chat | +---------+----------+----------+-------------+ | 18 | John | 7 | Tigré | | 27 | John | 14 | Roux | | 131 | John | 9 | Roux | | 157 | John | 1 | Brun | +---------+----------+----------+-------------+ 4 rows in set (0.00 sec)
Ce chat tout content n’a pas remarqué un truc… Retournez du côté de Talend et faites bien attention au nombre de lignes dans le flux entre la base de données et le tXmlMap.
200 lignes ! Cela veut dire que l’intégralité de la table est chargée en une fois au démarrage du job. C’est problématique :
- Si la table est lourde, ça va faire mal !
- Lorsque votre webservice sera en production, le job ne sera démarré qu’une seule fois. Toute mise à jour de la base sera ignorée après le démarrage du webservice.
Nous pouvons faire autrement, il est possible de lire la base de données en temps réel à chaque appel du webservice en utilisant la variable globalMap().
Lecture en base de données : en temps réel
Éditez le tXmlMap et affectez au paramètre Lookup Model la valeur Reload at each row. Un formulaire apparait afin d’ajouter des variables au sein de la globalMap(). Créez une nouvelle variable, appelez la nom_chat et reliez la au paramètre nom_chat de l’entrée row1.
De cette manière, la base de données sera rechargée à chaque fois que le webservice sera appelé. Afin de ne pas lire la base de données en entier nous allons utiliser notre variable en globalMap() dans la clause WHERE de la requête.
Le composant tXmlMap ressemble à ceci lorsque j’ai terminé :
Cliquez sur le composant tMylsqInput afin de modifier la requête et ajoutez une clause WHERE comme ceci :
WHERE nom_chat LIKE '" + globalMap.get("nom_chat") + "'
Enfin, exécutez à nouveau le job, testez à nouveau avec SoapUI pour vérifier que ça fonctionne mais la véritable plus-value se trouve du côté du job :
4 rows cette fois-ci ! Cela correspond à un appel au webservice qui m’a renvoyé 4 résultats. Ça fonctionne !
Troisième étape : mise en production
Votre webservice fonctionne ? Tout est OK ? Parfait ! Nous pouvons maintenant le mettre en production en utilisant Apache Karaf.
Pour faire simple, Karaf est un processus serveur embarqué en mode OSGi. Très simple d’utilisation, il nous permet ici de mettre en production vos webservices créés avec Talend.
Apache Karaf est un projet très complet et son utilisation ne se limite pas à cela, rendez-vous sur le site officiel pour obtenir plus d’informations.
Exportez votre webservice depuis Talend avec un clic droit sur le webservice puis Exporter le Service.
Il n’y a aucune option à configurer, le service est exporté au format .kar, format utilisé par Karaf.
L’exécutable du serveur Karaf se trouve dans le dossier Runtime_ESBE de Talend Open Studio.
Runtime_ESBE/container/bin
Lancez Karaf avec l’exécutable trun correspondant à votre système d’exploitation, vous devriez tomber sur cette console :
Rassurez-vous, il n’y a rien à faire avec cette console, Karaf propose une interface web accessible à cette adresse :
http://localhost:8040/system/console Login : karaf Mot de passe : karaf
La version de Karaf proposée par Talend est déjà configurée, nous aurions dû normalement lancer l’interface web manuellement et y définir un port d’écoute. Talend a sélectionné le port 8040 qui est également utilisé pour l’appel à vos webservices.
L’interface web affiche l’ensemble des bundles (services) lancés par Karaf, il y en a déjà quelques-uns par défaut.
Afin de mettre en production votre webservice, placez le fichier .kar généré par Talend dans le dossier suivant :
Runtime_ESBE/container/deploy
Rafraichissez l’interface web de Karaf afin d’afficher votre webservice dans la liste.
Enfin, pour accéder au webservice, l’adresse de la WSDL est la même qu’en développement mais le port devient 8040 au lieu de 8090.
- Développement avec Talend : http://localhost:8090/services/ChatsWS
- Production avec Karaf : http://localhost:8040/services/ChatsWS
N’oubliez pas d’ajouter ?wsdl à la fin de l’URL afin de la lire avec SoapUI.
Le webservice en production fonctionne aussi bien qu’en développement, les résultats sont les mêmes :
Félicitations, votre webservice est en production, vous pouvez maintenant l’utiliser sereinement.
[photo]
Merci pour ce tuto !
Bonjour et merci pour ce tuto!..
Je m’en suis inspiré pour définir un webservice presque identique sauf qu’en entrée j’ai défini 2 paramètres de type string (nom et ville). En sortie j’ai pratiquement la même structure avec des enregistrements de 4 valeurs de type string.
Une fois les mappages réalisés dans le composant Txmlmap, j’ai une erreur signalée par un ‘!’ sur fond rouge qui me dit que ‘out.payload:/tn:….’ have no source loop
Mes 2 paramètres en entrée sont définis en ‘loop’ et les mappages entre les différents composants sont réalisé comme dans le tuto.
Pouvez vous m’aider?
Cdt,
Benoît
Bonjour Benoit.
Avez-vous correctement sélectionné le loop element dans la sortie du txmlmap ?
Cdt, Thibaud.
Le loop element me semble bien configuré..
Si je ne laisse qu’un paramètre en entrée (nom ou ville) je n’ai plus l’erreur, mais j’ai besoin des 2..
Avez-vous correctement importé le schema XML sur le flux entrant (import from repository) ?
Il faut le faire dès que vous changez vos champs entrants ou sortants. La WSDL doit correspondre aux champs du txmlmap.
L’importation du schéma a été faite comme décrit.
J’ai finalement modifié la WSDL pour ajouter un niveau dans la hiérarchie en entrée:
demandes->demande-> – ville
– nom
avec demande en ‘loop element’
Résultat : plus de ‘!’ sur fond rouge. par contre à la compilation j’ai une erreur (même erreur avec 1 ou 2 éléments en entrée) :
Erreur (avec 1 élément en entrée):
————————————————
Ligne en erreur: 2202
Message détaillé: Syntax error, insert « ; » to complete Statement
Code correspondant:
—————————— row2HashKey.ville = treeNodeAPI_tXMLMap_1_TXMLMAP_OUT.get_String(« row1.payload:/tns:BtParNomRequest/ville_bt ») treeNodeAPI_tXMLMap_1_TXMLMAP_OUT.get_String(« row1.payload:/tns:BtParNomRequest/demandes/demande/nom_ville »);
row2HashKey.hashCodeDirty = true;
le ‘;’ demandé est suggéré entre les 2 ‘treeNode…’
Bonjour
Merci infiniment pour ce tutorial très pratique.
Savez vous s’il y a un moyen de ne pas utiliser Karaf , c’est à dire de générer un .jar totalement autonome , pour un service soap avec Talend ?
Bonjour,
C’est un très bonne question, à laquelle je n’ai pas de réponse précise.
J’ai cru comprendre que le format .kar correspond à Karaf. Je ne vois pas comment exporter le webservice autrement. Je ne vois pas non plus comment lancer un .kar sans Karaf.
Je trouve toutefois que Karaf est assez pratique à installer et utiliser. Quel est le problème ?
Thibaud.
Le contexte est compliqué, disons qu’il s’agit d’inclure un composant réalisé avec Talend dans une appli écrite en full PHP à ce jour. J’aurais aimé dans l’idéal qu’il y ait le moins de dépendances et de binaries possibles à intégrer. Merci pour votre réponse.
Bonjour,
Merci pou le tuto excellent.
@Emmanuel vous pouvez developper un job talend classique et l’exporter en tant que webservice, qui sera intégrer dans un tomcat par exemple.
Bonjour,
Merci beaucoup pour ce tutoriel !
J’ai une question : est ce qu’on peut définir des paramètres non obligatoires en entrée ?
Exemple : je fournis une adresse ( numéro, type voie et ville) et il me fournirait les informations demandées en sortie même si je ne fournis que le type de voie et la ville (des fois on n’a pas les numéros en base)
Merci par avance !
Cordialement
C’est magnifique!! Très bon tutoriel. Je n’ai pas encore mis en application tout ça mais j’ai trouvé les explications claires et structurées. J’en ai appris beaucoup en très peu de lecture.
Merci
salut monsieur merci pour votre tuto je veux te poser un question : si je.veux mettre en place un web service comme ce tuto et j ‘utilise par exemple 3 machines differents , comment je peux lier ces machines avec web service sachant que je veux travailler sur la meme base de donnees et si j affecte une insertion ou modification des données j’observe la résultat sur les autres machines !
Bonjour !
Merci infiniment pour le tuto qui est très parfait pour débuter en talend ESB.
Cependant, j’ai une question, je ne parviens pas à générer mon XML dans la métadonnées avec le clique droit sur le service. Sauriez-vous s’il vous plait me dire que faire?
Merci d’avance.