Automatisieren Sie Routinen zur automatischen Generierung von SOAP-Clients mit WSDL-Import für SBT und Scala

Die Arbeit mit SOAP wird oft schwierig, und der Umgang mit WSDL kann einen großen Beitrag zur Komplexität dieser Aufgabe leisten. Wirklich, es könnte die am wenigsten erwartete Sache sein, wenn Sie sich für eine moderne und ausgefallene Sprache wie beispielsweise Scala interessieren, die für ihre Reaktivität und asynchrone Art des Umgangs mit Anfragen bekannt ist. Tatsächlich wissen viele der Softwareentwickler, die in letzter Zeit ihren Weg in die Industrie gefunden haben, möglicherweise nicht einmal über SOAP- und WSDL-Protokolle Bescheid und werden schnell verärgert oder sogar wütend, wenn sie zum ersten Mal versuchen, eine Verbindung zu einem solchen Legacy-Dienst herzustellen. Sollten wir dies also insgesamt zugunsten eines modernen Technologie-Stacks ablehnen, oder gibt es vielleicht eine weniger schmerzhafte Lösung?


SOAP: Vermächtnis


Es ist schwer zu argumentieren, dass diese SOAP-Sache heutzutage ziemlich veraltet klingt, insbesondere im Gegensatz zum aktuellen Stand der Technologie. Das Schreiben eines WSDL-Clients von Grund auf mit Kotlin, Scala oder einer anderen modernen Sprache kann schmerzhaft sein, und das Fehlen einer geeigneten Dokumentation macht das Leben nicht einfacher. Aber ich habe gute Nachrichten für Sie, es gibt einen Lichtfleck im dunklen SOAP-Königreich. Nun, eigentlich ist WSDL selbst diejenige. Obwohl es schwer und etwas hässlich ist, hat es einen gewissen Vorteil. Die Übermäßigkeit des WSDL-Formats macht es ziemlich einfach, den Client- (und auch Server-) Code zu generieren, möglicherweise nicht für Menschen, aber definitiv für automatisierte Systeme.


Selbst im Vergleich zu modernen API-Spezifikationen könnte es tatsächlich mit OpenAPI- oder ausgefallenen Swagger-API-Konzepten mithalten, bei denen alles in einer sprachunabhängigen Spezifikation beschrieben wird. Dies ermöglicht enorme Möglichkeiten für die Interoperabilität zwischen verschiedenen Plattformen und Sprachen bis hin zur Implementierungsebene. Wenn beispielsweise ein .NET-Webdienst mit WSDL-Spezifikation verfügbar gemacht wird, kann ein anderer automatisch einen JVM-basierten Client generieren, um eine Verbindung zu ihm herzustellen, ohne dass die Konvertierung oder Inkompatibilität von Datenformaten beeinträchtigt wird.


WSDL Import Magic


Lassen Sie es uns weiter drehen und über die automatisierte Codegenerierung sprechen. Sie werden überrascht sein, aber die meisten unternehmensorientierten Plattformen, hauptsächlich Java und .NET, werden standardmäßig mit Tools zur Generierung von WSDL-Code geliefert. Zum Beispiel gibt es wsimport , das Teil einer JDK-Distribution ist. Solche Tools sind sehr leistungsfähig und sollten eine Aufgabe der automatischen Generierung von Ende zu Ende abdecken. Der einzige verbleibende Teil besteht darin, Ihre Geschäftslogik mit dem Clientcode zu verbinden und diesen zu verwenden.


Da wir uns derzeit mit dem Scala-Thema befassen, schauen wir uns das wsimport Tool von Java wsimport :


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

Der Befehl verwendet ein WSDL-Schema als erforderlichen Parameter. Grundsätzlich reicht es aus, eine ganze Reihe von POJOs und Schnittstellen zu erstellen, die mit allen richtigen Anmerkungen gekennzeichnet sind. Letztere machen tatsächlich den Trick: Dies ist im Wesentlichen das, was alle Dinge möglich macht. Bei der Ausführung verkabelt JVM Ihren Client-Code mit der sofort einsatzbereiten internen Web-Service-Client-Implementierung, sodass Sie sich nicht viel um Low-Level-Netzwerke und E / A kümmern müssen. Der Rest des Geschäfts besteht darin, die Vor- und Nachteile ordnungsgemäß zu behandeln und mit Fehlern und Ausnahmen vorsichtig umzugehen.


Bringen Sie die Automatisierung mit SBT auf die nächste Stufe


Okay, es ist Zeit für ein paar praktische Übungen. Stellen Sie sich vor, wir haben einige SOAP-Webdienste, die wir ebenfalls verbinden müssen, und sie machen WSDL verfügbar. Ich habe einige absichtlich zum Testen genommen, natürlich nur aus Gründen der Wissenschaft und Bildung. Führen Sie den Codegenerator aus:


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

Es wird eine Reihe von Java-Rohcode im Ausgabeordner erzeugt. Wir könnten mit der Verbindung unserer Geschäftslogik fortfahren, wie oben vorgeschlagen. Aber warten Sie eine Sekunde, was ist, wenn sich die Serverseite ändert - wir werden es erst im Moment der tatsächlichen Codeausführung bemerken (oder im Moment des Fehlschlags der Integrationstests, wenn wir welche haben). Nicht schön. Es wird schnell gar nicht mehr schön, wenn Sie daran denken, all diesen Java-Bean-Code in Ihr makelloses Scala-Repository zu übernehmen.


Natürlich wäre es viel schöner, all diese Dinge automatisch zu generieren und die Dinge schlank und sauber zu halten. Ein erster Schritt hierfür wäre, das Abrufen aller WSDL-Klassen mit einem Befehl zu automatisieren und daraus ein Shell-Skript zu erstellen. Ich habe tatsächlich eine für Sie gemacht, damit Sie einen Blick darauf werfen können: wsdl_import.sh .


Dann könnten wir es einfach mit einer Build-Aufgabe abschließen: Nehmen wir als Beispiel SBT, da wir auf Scala sind, also sollte so etwas funktionieren:


 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.") } 

Quelle


Jetzt müssen wir aus offensichtlichen Gründen sicherstellen, dass wir den gesamten Code haben, bevor der Scala-Teil kompiliert wird. Einfach, wir haben SBT, also müssen wir nur das Shell-Skript als SBT-Aufgabe wie oben ausführen und die Dinge in der richtigen Reihenfolge ausführen, richtig? Nun, im wirklichen Leben ist es etwas komplizierter. Ohne auf die Details der Funktionsweise von SBT einzugehen, wird es viel einfacher, wenn wir diesen WSDL-Java-Teil in ein eigenständiges Unterprojekt unterteilen und eine ordnungsgemäße Abhängigkeit in der Master-SBT-Konfiguration herstellen.


 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) 

Quelle


Wenn Sie das Masterprojekt kompilieren, stellt SBT zunächst sicher, dass das Unterprojekt bereits kompiliert ist. Aber es gibt einen Haken: Wenn Sie gerade Ihr Repository ausgecheckt haben, haben Sie die Kompilierung möglicherweise nicht ausgeführt. Wenn Sie es also zum ersten Mal im Editor öffnen, fehlen natürlich einige der Abhängigkeiten. Hoffentlich müssen Sie nur einen sbt-Kompilierungsbefehl ausführen und möglicherweise das Projekt in IDE aktualisieren.


Es kann eine weitere Einschränkung geben, wenn Sie Ihre Scala-Anwendung als eigenständiger Client oder in einem schlanken Webcontainer ausführen (z. B. Netty, wenn Sie Play Framework verwenden). In diesem Fall fehlt der Anwendungslaufzeit höchstwahrscheinlich das Implementierungsbit, mit dem JVM dank moderner JRE-Versionen und des Java Jigsaw-Projekts die SOAP-Magie für Sie ausführen kann. Sie müssen jedoch nicht in Panik geraten. Fügen Sie einfach ein paar Bibliotheken zu Ihrer Abhängigkeitsliste hinzu oder werfen Sie eine einzelne rt.jar aus Ihrer JRE-Distribution als nicht verwaltete Abhängigkeit:


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

Als Fazit


Okay, als Zusammenfassung: Wir haben ein bisschen über SOAP und WSDL gelernt und hoffentlich erkannt, dass es dank all dieser Codegeneratoren und der übermäßigen WSDL-Spezifikation kein Albtraum ist, damit zu arbeiten. Wir haben auch herausgefunden, wie ein schmutziger Job automatisiert werden kann, und einen Weg gefunden, unsere Repositories makellos und sauber von unerwünschtem Boilerplate-Code zu halten. Um die Kompilierungsreihenfolge und -abhängigkeiten richtig zu konfigurieren, waren einige SBT-Kenntnisse erforderlich, aber es sollte schließlich reibungslos funktionieren. Um die Sache noch weiter zu vereinfachen, habe ich eine kleine Bootstrap-Vorlage erstellt, die Ihnen beim nächsten Start eines Projekts helfen soll: https://github.com/sainnr/sbt-scala-wsdl-template . Ich hoffe, Sie haben diese kleine Reise in die Vergangenheit genossen!


Referenzen



Bitte schreiben Sie mir eine Nachricht, wenn Sie Tippfehler oder Fehler sehen.


Dieser Artikel wurde ursprünglich in meinem Blog fullstackme.co.uk mit kleinen Änderungen veröffentlicht.

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


All Articles