Automatisez les routines de génération automatique de clients SOAP avec l'importation WSDL pour SBT et Scala

Travailler avec SOAP devient souvent délicat, et gérer WSDL peut être une énorme contribution à la complexité de cette tâche. Vraiment, ce pourrait être la chose la moins attendue à affronter lorsque vous êtes dans un langage moderne et sophistiqué comme, par exemple, Scala, qui est bien connu pour sa réactivité et sa manière asynchrone de traiter les demandes. En fait, de nombreux développeurs de logiciels qui ont fait leur entrée dans l'industrie assez récemment, ne connaissent peut-être même pas les protocoles SOAP et WSDL, et deviennent rapidement ennuyés ou même enragés lorsqu'ils essaient pour la première fois de se connecter à un tel service hérité. Alors, devrions-nous déprécier tout cela au profit d'une pile de technologies modernes, ou peut-être qu'il existe une solution moins douloureuse?


SAVON: Héritage


Il est difficile de prétendre que cette chose SOAP semble assez obsolète de nos jours, en particulier en contraste avec l'état actuel de la technologie. Écrire un client WSDL à partir de zéro avec Kotlin, Scala ou un autre langage moderne pourrait être pénible, et le manque de documentation appropriée ne facilite pas la vie. Mais j'ai une bonne nouvelle pour vous, il y a une tache de lumière dans le royaume du savon noir. Eh bien, en fait WSDL lui-même est celui-là. En dépit d'être lourd et quelque peu laid, il a un certain avantage. L'excès du format WSDL facilite la génération du code client (et également serveur), peut-être pas pour les humains mais certainement pour les systèmes automatisés.


Même par rapport aux spécifications API modernes, il pourrait en fait rester à égalité avec OpenAPI ou les concepts sophistiqués de l'API Swagger où tout est décrit dans une spécification indépendante du langage. Cela offre d'énormes possibilités d'interopérabilité entre différentes plates-formes et langues, jusqu'au niveau de mise en œuvre. Par exemple, si l'un expose un service Web .NET avec des spécifications WSDL, un autre pourrait générer automatiquement un client basé sur JVM pour s'y connecter avec peu ou pas de douleur de conversion ou d'incompatibilité des formats de données.


Importation WSDL Magic


Allons plus loin et parlons de la génération de code automatisée. Vous pourriez être surpris, mais la plupart des plates-formes d'entreprise, principalement Java et .NET, sont livrées avec des outils de génération de code WSDL prêts à l'emploi. Par exemple, il y a wsimport qui fait partie d'une distribution JDK. Ces outils sont assez puissants et devraient couvrir une tâche de génération automatique de bout en bout. La seule partie restante est de connecter votre logique métier au code client et de l'utiliser.


Donc, puisque nous sommes actuellement sur le thème Scala, regardons plus en profondeur l'outil wsimport de Java:


 wsimport -p stockquote http://stockquote.example.com/quote?wsdl 

La commande prend un schéma WSDL comme paramètre requis, et en gros, il suffit juste de produire un ensemble complet de POJO et d'interfaces, marqués de toutes les annotations appropriées. Ces derniers font vraiment l'affaire: c'est essentiellement ce qui rend tout possible. Une fois exécutée, la JVM connecte votre code client avec l'implémentation du client de service Web interne, qui sort de la boîte, de sorte que vous n'avez pas à vous soucier beaucoup des réseaux de bas niveau et des E / S. Le reste de l'entreprise consiste à gérer correctement les tenants et aboutissants et à faire attention aux erreurs et exceptions.


Faites passer l'automatisation au niveau supérieur avec SBT


D'accord, il est temps de passer à l'action. Imaginez que nous ayons certains services Web SOAP que nous devons également connecter, et qu'ils exposent WSDL. J'en ai délibérément pris quelques-uns pour des tests, pour le bien de la science et de l'éducation seulement, bien sûr. Exécutez le générateur de code:


 wsimport -s ../src/main/java -extension -p your.package.wsdl.nl \ -XadditionalHeaders -Xnocompile \ http://webservices.oorsprong.org/websamples.countryinfo/CountryInfoService.wso?WSDL 

Il produit un certain nombre de code Java brut dans le dossier de sortie. Nous pourrions procéder à la connexion de notre logique métier, comme suggéré ci-dessus. Mais attendez une seconde, que se passe-t-il si le côté serveur change - nous n'en serons conscients qu'au moment de l'exécution réelle du code (ou au moment de l'échec des tests d'intégration, si nous en avons). Pas jolie. Cela devient vite pas joli du tout si vous songez à valider tout ce code de bean Java standard dans votre référentiel Scala vierge.


Bien sûr, il serait bien plus agréable de générer tout cela automatiquement et de garder les choses propres et propres. Une première étape pour cela serait d'automatiser l'obtention de toutes les classes WSDL avec une seule commande et d'en faire un script Shell. En fait, j'en ai fait un pour vous afin que vous puissiez y jeter un œil: wsdl_import.sh .


Ensuite, nous pourrions simplement l'envelopper avec une tâche de construction: prenons SBT comme exemple, puisque nous sommes sur Scala, donc quelque chose comme ça devrait fonctionner:


 lazy val wsdlImport = TaskKey[Unit]("wsdlImport", "Generates Java classes from WSDL") wsdlImport := { val wsdlSources = "./wsdl/src/main/java" val d = file(wsdlSources) if (d.isDirectory) { // don't forget to rename to your fav one in line with WSDL generating sh val gen = file(s"$wsdlSources/github/sainnr/wsdl") if (!gen.exists() || gen.listFiles().isEmpty) { import sys.process._ println("[wsdl_import] Importing Java beans from WSDL...") "./wsdl/bin/wsdl_import.sh" ! } else println("[wsdl_import] Looks like WSDL is already imported, skipping.") } else println(s"[wsdl_import] Make sure the directory ${d.absolutePath} exists.") } 

Source


Maintenant, nous devons nous assurer que nous avons tout ce code avant la compilation de Scala, pour des raisons évidentes. Facile, nous avons SBT donc nous avons juste besoin d'exécuter le script Shell comme une tâche SBT comme ci-dessus et d'exécuter les choses dans le bon ordre, correct? Eh bien, c'est un peu plus compliqué dans la vraie vie. Sans entrer dans la plupart des détails sur le fonctionnement de SBT, les choses deviennent beaucoup plus faciles si nous séparons cette partie WSDL-Java en un sous-projet autonome et créons une dépendance appropriée dans la configuration SBT principale.


 lazy val wsdl = (project in file("wsdl")) .settings ( publishSettings, sources in (Compile, doc) := Seq.empty ) lazy val root = (project in file(".")) .aggregate(wsdl) .dependsOn(wsdl) 

Source


Lorsque vous compilez le projet maître, SBT s'assure d'abord que le sous-projet est déjà compilé. Mais il y a un hic: lorsque vous venez de vérifier votre référentiel, vous n'avez peut-être pas exécuté la compilation. Donc, lorsque vous l'ouvrez pour la première fois dans l'éditeur, certaines des dépendances seront bien sûr manquantes. Heureusement, la seule chose dont vous avez besoin est d'exécuter une commande de compilation sbt et, peut-être, d'actualiser le projet dans IDE.


Il peut y avoir une autre mise en garde si vous exécutez votre application Scala en tant que client autonome ou dans un conteneur Web allégé (par exemple Netty si vous utilisez Play Framework). Dans ce cas, il est très probable que le runtime d'application ne contienne pas le bit d'implémentation qui aide JVM à faire la magie SOAP pour vous, grâce aux versions JRE modernes et au projet Jigsaw Java. Pas besoin de paniquer cependant, ajoutez simplement quelques bibliothèques à votre liste de dépendances, ou lancez un seul rt.jar depuis votre distribution JRE en tant que dépendance non gérée:


  unmanagedJars in Test += Attributed.blank( file(System.getenv("JAVA_HOME") + "/jre/lib") ) 

En conclusion


D'accord, pour récapituler: nous avons appris un peu sur SOAP et WSDL et nous espérons que ce n'est pas un cauchemar avec lequel travailler, grâce à tous ces générateurs de code et à la spécification WSDL excessive. Nous avons également trouvé comment automatiser un sale boulot et avons trouvé un moyen de garder nos référentiels vierges et propres du code indésirable. Il a fallu une certaine connaissance de SBT pour configurer correctement l'ordre de compilation et les dépendances, mais après tout, cela devrait fonctionner assez bien. Pour simplifier encore les choses, j'ai créé un petit modèle de bootstrap qui devrait vous aider à démarrer un projet la prochaine fois: https://github.com/sainnr/sbt-scala-wsdl-template . J'espère que vous avez apprécié ce petit voyage dans le passé!


Les références



Envoyez-moi un message si vous voyez des fautes de frappe ou des erreurs.


Cet article a été initialement publié sur mon blog fullstackme.co.uk avec peu de modifications.

Source: https://habr.com/ru/post/fr470349/


All Articles