Статьи

Автоматизируйте процедуры автоматической генерации клиента SOAP с помощью импорта WSDL для SBT и Scala

Автоматизируйте процедуры автоматической генерации клиента SOAP.

Работать с SOAP часто бывает сложно, а работа с WSDL может стать огромным вкладом в сложность этой задачи. На самом деле, это может быть наименее ожидаемая вещь, с которой вы столкнетесь, если вы находитесь на современном и модном языке, таком как, например, Scala, который хорошо известен своей реактивностью и асинхронным способом обработки запросов.

Фактически, многие разработчики программного обеспечения, которые недавно вошли в отрасль, могут даже не знать о протоколах SOAP и WSDL и быстро раздражаться или даже злиться при первой попытке подключения к такой устаревшей службе. Итак, должны ли мы отказаться от этого в пользу современного технологического стека или есть менее болезненное решение?


Вам также может понравиться: 
Понимание WSDL

МЫЛО: Наследие

Трудно утверждать, что эта вещь SOAP звучит довольно устаревшей в настоящее время, особенно в отличие от текущего состояния технологии. Написание клиента WSDL с нуля с использованием Kotlin, Scala или другого современного языка может быть проблемой, а отсутствие надлежащей документации для него не облегчает жизнь. Но у меня для вас хорошие новости; в темном королевстве SOAP есть пятно света.

Ну, на самом деле, WSDL является единственным. Несмотря на то, что он тяжелый и несколько уродливый, у него есть определенное преимущество. Чрезмерность формата WSDL делает довольно простым генерирование клиентского (а также серверного) кода (возможно, не для людей, но определенно для автоматизированных систем).

Даже по сравнению с современными API-спецификациями, он может фактически остаться на уровне OpenAPI или причудливых концепций Swagger API, где все описано в не зависящей от языка спецификации. Это открывает огромные возможности для взаимодействия между различными платформами и языками, вплоть до уровня реализации. Например, если один предоставляет, скажем, веб-сервис .NET со спецификацией WSDL, другой может автоматически сгенерировать клиент на основе JVM, чтобы подключиться к нему практически без проблем при преобразовании или несовместимости форматов данных.

WSDL Import Magic

Давайте продолжим и поговорим об автоматической генерации кода. Вы можете быть удивлены, но большинство корпоративных платформ, в основном Java и .NET, поставляются с инструментами генерации кода WSDL из коробки. Например, есть wsimport, который входит в дистрибутив JDK. Такие инструменты достаточно мощные и должны охватывать задачи автоматической генерации из конца в конец. Единственная оставшаяся часть — это соединить вашу бизнес-логику с клиентским кодом и использовать его.

Итак, поскольку мы сейчас занимаемся темой Scala, давайте углубимся в wsimportинструмент Java :

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

Команда принимает схему WSDL в качестве обязательного параметра, и в основном этого достаточно для создания целого набора POJO и интерфейсов, помеченных всеми надлежащими аннотациями. Последние на самом деле делают свое дело: это то, что делает все возможное. При выполнении JVM связывает ваш клиентский код с внутренней клиентской реализацией веб-службы, которая выходит из коробки, поэтому вам не нужно сильно беспокоиться о низкоуровневых сетях и IO. Остальная часть бизнеса — правильно обрабатывать входы и выходы и быть осторожным с ошибками и исключениями.

Вывести автоматизацию на новый уровень с SBT

Хорошо, пришло время для некоторых практических. Представьте, что у нас есть несколько веб-сервисов SOAP, к your.server.com которым нам нужно подключиться, и они предоставляют WSDL: скажем, для управления любым видом заказов. Запустите генератор кода при указании на  orders веб-сервис:

wsimport -s ../src/main/java -extension -p your.package.wsdl.orders \
  -XadditionalHeaders -Xnocompile \
  http://your.server.com/orders?wsdl

Она производит ряд сырого кода Java в выходной папке со всеми пакетами с префиксом , как указано выше: your.package.wsdl.orders. Мы могли бы продолжить подключение нашей бизнес-логики, как предлагалось ранее. Но подождите секунду, что, если изменения на стороне сервера? Мы узнаем об этом только в момент фактического выполнения кода (или в момент сбоя интеграционных тестов, если он у нас есть). Не красиво Это быстро становится уродливым, если вы подумаете о добавлении всего этого стандартного Java-бина-кода в ваш первоначальный репозиторий Scala.

Конечно, было бы гораздо приятнее автоматически генерировать все эти вещи и сохранять их стройными и чистыми. Первым шагом для этого было бы автоматизировать получение всех классов WSDL с помощью одной команды и сделать из этого сценарий Shell. Я действительно сделал один для вас, чтобы вы могли посмотреть: wsdl_import.sh .

Тогда мы могли бы просто обернуть его задачей сборки: давайте возьмем SBT в качестве примера, так как мы находимся на Scala, поэтому что-то вроде этого должно работать:

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

Сырой код на GitHub

Теперь нам нужно убедиться, что у нас есть весь этот код, прежде чем Scala будет компилироваться по понятным причинам. Просто-напросто, у нас есть SBT, поэтому нам просто нужно выполнить сценарий Shell как задачу SBT, как описано выше, и выполнить все в правильном порядке, верно? Ну, это немного сложнее в реальной жизни. Не вдаваясь в подробности работы SBT, все станет намного проще, если мы разделим эту часть WSDL-Java на самоподдерживающийся подпроект и создадим правильную зависимость в основной конфигурации SBT.

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)

Сырой код на GitHub

Когда вы компилируете главный проект, SBT сначала гарантирует, что подпроект уже скомпилирован. Но есть одна загвоздка: когда вы только что проверили свой репозиторий, вы, возможно, не выполнили компиляцию. Поэтому, когда вы впервые откроете его в редакторе, некоторые зависимости, конечно, будут отсутствовать. Надеюсь, единственное, что вам нужно, это запустить sbt compileкоманду и, возможно, обновить проект в IDE.

Может быть другое предостережение, если вы запускаете приложение Scala в качестве автономного клиента или в компактном веб-контейнере (например, Netty, если вы используете Play Framework). В этом случае весьма вероятно, что во время выполнения приложения будет отсутствовать бит реализации, который помогает JVM сделать магию SOAP за вас, благодаря современным версиям JRE и проекту Java Jigsaw. Не нужно паниковать, просто добавьте несколько библиотек в список зависимостей или добавьте один rt.jar из дистрибутива JRE в качестве неуправляемой зависимости:

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

Заключение

Итак, подведем итоги: мы немного узнали о SOAP и WSDL и, надеюсь, поняли, что работать не с этим кошмаром, благодаря всем этим генераторам кода и чрезмерным спецификациям WSDL. Мы также выяснили, как автоматизировать грязную работу и нашли способ сохранить наши репозитории нетронутыми и чистыми от нежелательного стандартного кода.

Потребовалось некоторое знание SBT, чтобы правильно настроить порядок компиляции и зависимости, но в конце концов, он должен работать довольно гладко. Чтобы еще больше упростить процесс, я создал небольшой шаблон начальной загрузки, который поможет вам запустить проект в следующий раз: https://github.com/sainnr/sbt-scala-wsdl-template .

Надеюсь, вам понравилось это маленькое путешествие в прошлое!

Дальнейшее чтение

Создание веб-службы SOAP с помощью веб-служб Spring Boot Starter

Top 19 вопросов о SOAP-интервью