Разработка SOAP-сервиса на платформе WSO2

от автора

В прошлом посте мы начали рассказывать о разработке на платформе WSO2 и сделали REST API-сервис. Сегодня мы продолжаем тему: в этом посте поделюсь с вами тем, как мы в WSO2 создаем SOAP-сервисы. В этом посте я делаю акцент на различиях, поэтому на случай каких-то общих вопросов можете параллельно открыть пост про REST API.

В WSO2 Integration Studio создаем новый проект (File – New – Integration Project). Назовем его, например, Rosstat Service. Не забываем создать RegistryResources, поскольку SOAP-сервис в любом случае предусматривает WSDL/XSD, а их нужно где-то хранить

Добавляем в каждый из отмеченных каталогов пустой файл с именем «.gitkeep» для контроля версий:

Далее настраиваем остальные параметры в зависимости от проекта. Все ссылки репозитория WSO2 Nexus во всех файлах «pom.xml» меняем на ваши собственные. У нас, соответственно, https://maven.wso2.org/nexus/content/groups/wso2-public/ меняется на https://nexus.gts.rus.socgen/repository/maven-wso2-public/.

Создаем шаблоны

Создадим шаблон для вызова внешнего сервиса CallAPI.

В типе шаблона нужно выбрать Sequence Template. С точки зрения кода шаблон будет таким же, как и при создании REST API-сервиса, поскольку мы принимаем SOAP, а вызываем REST:

<template name="MOEX_callAPI_Template" xmlns="http://ws.apache.org/ns/synapse">   <parameter defaultValue="" isMandatory="false" name="setCallEndpointName"/>   <parameter defaultValue="" isMandatory="false" name="setEndpointURL"/>   <parameter defaultValue="" isMandatory="false" name="setEndpointURL_Suffix"/>   <parameter defaultValue="" isMandatory="false" name="setQueryParams"/>   <sequence>       <property expression="get-property('file', $func:setEndpointURL)" name="ENV_ENDPOINT_URL" scope="default" type="STRING"/>       <filter regex="true" source="boolean($ctx:ENV_ENDPOINT_URL) and string-length($ctx:ENV_ENDPOINT_URL) > 0">           <then/>           <else>               <property expression="get-property('env', $func:setEndpointURL)" name="ENV_ENDPOINT_URL" scope="default" type="STRING"/>           </else>     </filter>       <switch source="boolean($func:setQueryParams) and string-length($func:setQueryParams) > 0">           <case regex="true">               <property expression="fn:concat($ctx:ENV_ENDPOINT_URL, $func:setEndpointURL_Suffix, '?', $func:setQueryParams)" name="uri.var.endpointURL_FullAddress" scope="default" type="STRING"/>           </case>           <default>             <property expression="fn:concat($ctx:ENV_ENDPOINT_URL, $func:setEndpointURL_Suffix)" name="uri.var.endpointURL_FullAddress" scope="default" type="STRING"/>           </default>     </switch>     <class description="OutReqLoggerTXT" name="ru.rosbank.mediator.LoggerMediatorTXT">           <property name="logLevel" value="DEBUG"/>           <property name="ReqType" value="OutRequest"/>           <property expression="fn:concat('sending request to endpointURL_FullAddress=', $ctx:uri.var.endpointURL_FullAddress)" name="Payload"/>       </class>       <call>           <endpoint key-expression="$func:setCallEndpointName"/>       </call>   </sequence>   </template> 

Теперь создаем шаблон для обработки ошибок SOAPFault. Здесь нужно обратить внимание, какая версия протокола SOAP используется, 1.1 или 1.2. От этого будут зависеть некоторые параметры формирования ошибки, в частности, различаться ContentType. Вот код обработчика для SOAP 1.1:

<template name="Rosstat_SOAPFault_Template" xmlns="http://ws.apache.org/ns/synapse">  <parameter defaultValue="" isMandatory="false" name="MessageID"/>  <parameter defaultValue="" isMandatory="false" name="ErrorText"/>  <parameter defaultValue="" isMandatory="false" name="Exception"/>  <sequence>      <payloadFactory description="ExceptionPayload" media-type="xml">          <format>              <m:Exception xmlns:m="http://wso2.rosbank.ru/types/Fault">                  <msgID xmlns="">$1</msgID>                  <text xmlns="">$2</text>                  <exception xmlns="">$3</exception>              </m:Exception>          </format>          <args>              <arg evaluator="xml" expression="$func:MessageID"/>              <arg evaluator="xml" expression="$func:ErrorText"/>              <arg evaluator="xml" expression="$func:Exception"/>          </args>      </payloadFactory>      <enrich description="body to property">          <source clone="true" type="body"/>          <target property="MESSAGE_PAYLOAD" type="property"/>      </enrich>      <makefault description="SoapFault" version="soap11">          <code value="soap11Env:Server" xmlns:soap11Env="http://schemas.xmlsoap.org/soap/envelope/"/>          <reason value="Error message processing"/>          <detail expression="get-property('MESSAGE_PAYLOAD')"/>      </makefault>      <propertyGroup description="removeHeaders">          <property action="remove" name="TRANSPORT_HEADERS" scope="axis2"/>          <property action="remove" name="EXCESS_TRANSPORT_HEADERS" scope="axis2"/>      </propertyGroup>      <propertyGroup description="setHeaders">          <property name="HTTP_SC" scope="axis2" type="STRING" value="500"/>          <property name="HTTP_SC_DESC" scope="axis2" type="STRING" value="Internal Server Error"/>          <property name="MESSAGE_FORMAT" scope="default" type="STRING" value="soap11"/>          <property name="messageType" scope="axis2" type="STRING" value="text/xml"/>          <property name="ContentType" scope="axis2" type="STRING" value="text/xml"/>          <property name="Content-Type" scope="transport" type="STRING" value="text/xml;charset=UTF-8"/>          <property name="RESPONSE" scope="default" type="STRING" value="true"/>      </propertyGroup>  </sequence>  </template>

При возникновении ошибки этот обработчик передает XML-сообщение с уникальным id, по которому можно будет легко ее найти в логах. Также не забудьте проставить свою версию SOAP для SOAPFault: description="SoapFault" version="soap11".

А вот код обработчика для SOAP 1.2:

<template name="Rosstat_SOAPFault_Template" xmlns="http://ws.apache.org/ns/synapse">      <parameter defaultValue="" isMandatory="false" name="MessageID"/>     <parameter defaultValue="" isMandatory="false" name="ErrorText"/>     <parameter defaultValue="" isMandatory="false" name="Exception"/>     <sequence>         <payloadFactory description="ExceptionPayload" media-type="xml">             <format>                 <m:Exception xmlns:m="http://wso2.rosbank.ru/types/Fault">                     <msgID xmlns="">$1</msgID>                     <text xmlns="">$2</text>                     <exception xmlns="">$3</exception>                 </m:Exception>             </format>             <args>                 <arg evaluator="xml" expression="$func:MessageID"/>                 <arg evaluator="xml" expression="$func:ErrorText"/>                 <arg evaluator="xml" expression="$func:Exception"/>             </args>         </payloadFactory>         <enrich description="body to property">             <source clone="true" type="body"/>             <target property="MESSAGE_PAYLOAD" type="property"/>         </enrich>         <makefault description="SoapFault" version="soap12">             <code value="soap12Env:Receiver" xmlns:soap12Env="http://www.w3.org/2003/05/soap-envelope"/>             <reason value="Error message processing"/>             <detail expression="get-property('MESSAGE_PAYLOAD')"/>         </makefault>         <propertyGroup description="removeHeaders">             <property action="remove" name="TRANSPORT_HEADERS" scope="axis2"/>             <property action="remove" name="EXCESS_TRANSPORT_HEADERS" scope="axis2"/>         </propertyGroup>         <propertyGroup description="setHeaders">             <property name="HTTP_SC" scope="axis2" type="STRING" value="500"/>             <property name="HTTP_SC_DESC" scope="axis2" type="STRING" value="Internal Server Error"/>             <property name="MESSAGE_FORMAT" scope="default" type="STRING" value="soap12"/>             <property name="messageType" scope="axis2" type="STRING" value="application/soap+xml"/>             <property name="ContentType" scope="axis2" type="STRING" value="application/soap+xml"/>             <property name="Content-Type" scope="transport" type="STRING" value="application/soap+xml;charset=UTF-8"/>             <property name="RESPONSE" scope="default" type="STRING" value="true"/>         </propertyGroup>     </sequence> </template>

Создаем обработчики

Теперь создаем общие шаги — Sequence — для обработки входящих ошибок:

FaultSequence перехватывает исключения, которые могут произойти при обработке запроса, и вызывает шаблон SOAPFault, который мы только что сделали: 

Создадим обработчик Inbound для приема входящих запросов:

<sequence name="Rosstat_InboundSequence" onError="Rosstat_FaultSequence" trace="disable" xmlns="http://ws.apache.org/ns/synapse">  <propertyGroup description="setProperty">      <property name="ENV_SERVICE_NAME" scope="default" type="STRING" value="RosstatService"/>      <property expression="$axis2:TransportInURL" name="ENV_REST_URL_POSTFIX" scope="default" type="STRING"/>      <property expression="fn:substring-after(get-property('MessageID'), 'uuid:')" name="ENV_MESSAGE_ID" scope="default" type="STRING"/>      <property expression="local-name(//soapenv:Envelope/soapenv:Body/*[1])" name="ENV_METHOD_NAME" scope="default" type="STRING" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"/>      <property expression="fn:substring-after($axis2:TransportInURL, '?')" name="ENV_QUERY_PARAMS" scope="default" type="STRING"/>      <property expression="string('')" name="ENV_EMPTY_STRING" scope="default" type="STRING"/>      <property expression="$axis2:REMOTE_ADDR" name="ENV_IP_ADDRESS" scope="default" type="STRING"/>  </propertyGroup>  <class description="InReqLoggerTXT" name="ru.rosbank.mediator.LoggerMediatorTXT">      <property name="logLevel" value="DEBUG"/>      <property name="ReqType" value="Begin"/>      <property name="Payload" value="Request accepted..."/>  </class>  </sequence>

В параметре ENV_SERVICE_NAME указываем название сервиса. Это же имя будет использоваться в LoggerService для записи логов в отдельный файл. В параметре «onError» здесь и далее в инструкции указываем ссылку на ранее созданный обработчик ошибок: onError="Rosstat_FaultSequence".

Здесь есть небольшие отличия от REST. Сгенирировав uuid, мы идем в SOAP Envelope – Body и оттуда получаем название метода. В протоколе SOAP название метода передается именно в теле.

Теперь сделаем Outbound — обработчик, который будет заносить в лог факт обработки запроса.

<sequence name="Rosstat_OutboundSequence" onError="Rosstat_FaultSequence" trace="disable" xmlns="http://ws.apache.org/ns/synapse">  <class description="InResLoggerTXT" name="ru.rosbank.mediator.LoggerMediatorTXT">      <property name="logLevel" value="DEBUG"/>      <property name="ReqType" value="End"/>      <property name="Payload" value="Request processed success"/>  </class>  </sequence>

И наконец, новый обработчик, которого не было в REST API. UnsupportedSequence используется для обработки ошибки, когда метод был объявлен в WSDL, но не был реализован (или мы сами не хотим его выставлять). 

Здесь тоже используется шаблон SOAPFault. В сообщении ошибки мы выдаем «Unsupported service»:

<sequence name="Rosstat_UnsupportedService_Sequence" onError="Rosstat_FaultSequence" trace="disable" xmlns="http://ws.apache.org/ns/synapse">  <class description="InReqLoggerSOAP" name="ru.rosbank.mediator.LoggerMediatorSOAP">      <property name="logLevel" value="INFO"/>      <property name="ReqType" value="InRequest"/>      <property name="isLogHeader" value="true"/>      <property name="isLogPayload" value="true"/>  </class>  <call-template description="SoapFault" target="Rosstat_SOAPFault_Template">      <with-param name="MessageID" value="{$ctx:ENV_MESSAGE_ID}"/>      <with-param name="ErrorText" value="Unsupported service"/>      <with-param name="Exception" value="{$ctx:ENV_EMPTY_STRING}"/>  </call-template>  <class description="InResLoggerSOAP" name="ru.rosbank.mediator.LoggerMediatorSOAP">      <property name="logLevel" value="INFO"/>      <property name="ReqType" value="InResponse"/>      <property name="isLogHeader" value="true"/>      <property name="isLogPayload" value="true"/>  </class>  </sequence>

Еще один обработчик, которого не было в REST API — обработчик конкретного метода (операции) GetOrganizationInfo. В REST API мы это делали на уровне API с помощью <resource>, здесь это устроено иначе.

 Логируем запрос, вызываем HTPP-сервис и логируем ответ: 

<sequence name="Rosstat_GetOrganizationInfo_Sequence" onError="Rosstat_FaultSequence" trace="disable" xmlns="http://ws.apache.org/ns/synapse">  <class description="InReqLoggerSOAP" name="ru.rosbank.mediator.LoggerMediatorSOAP">      <property name="logLevel" value="INFO"/>      <property name="ReqType" value="InRequest"/>      <property name="isLogHeader" value="true"/>      <property name="isLogPayload" value="true"/>  </class>  <sequence key="Rosstat_GetOrganizationInfo_HTTPRequest_Sequence"/>  <class description="InResLoggerSOAP" name="ru.rosbank.mediator.LoggerMediatorSOAP">      <property name="logLevel" value="INFO"/>      <property name="ReqType" value="InResponse"/>      <property name="isLogHeader" value="true"/>      <property name="isLogPayload" value="true"/>  </class>  </sequence>

Теперь нам нужно создать обработчик запросов.

Здесь мы удаляем все транспортные заголовки, превращаем SOAP в JSON, задаем формат из трех полей и  ContentType, логируем запрос, вызываем CallTemplate и проверяем, что вернулся код 200. Если да, то мы вызываем sequence для обратной трансформации, если нет — логируем ошибку, вызываем шаблон SOAPfault:

<sequence name="Rosstat_GetOrganizationInfo_HTTPRequest_Sequence" onError="Rosstat_FaultSequence" trace="disable" xmlns="http://ws.apache.org/ns/synapse">  <propertyGroup description="removeHeaders">      <property action="remove" name="TRANSPORT_HEADERS" scope="axis2"/>      <property action="remove" name="EXCESS_TRANSPORT_HEADERS" scope="axis2"/>  </propertyGroup>  <payloadFactory description="MappingIn" media-type="json">      <format>{"okpo":"$1", "inn":"$2", "ogrn":"$3"}</format>      <args>          <arg evaluator="xml" expression="//p:okpo/text()" xmlns:p="http://ru.rosbank.servicemix/cd/client"/>          <arg evaluator="xml" expression="//p:inn/text()" xmlns:p="http://ru.rosbank.servicemix/cd/client"/>          <arg evaluator="xml" expression="//p:ogrn/text()" xmlns:p="http://ru.rosbank.servicemix/cd/client"/>      </args>  </payloadFactory>  <propertyGroup description="setHeader">      <property name="messageType" scope="axis2" type="STRING" value="application/json"/>  </propertyGroup>  <class description="OutReqLoggerJSON" name="ru.rosbank.mediator.LoggerMediatorJSON">      <property name="logLevel" value="INFO"/>      <property name="ReqType" value="OutRequest"/>      <property name="isLogHeader" value="true"/>      <property name="isLogPayload" value="true"/>  </class>  <call-template description="callRosstat" onError="Rosstat_FaultSequence" target="Rosstat_callAPI_Template">      <with-param name="setCallEndpointName" value="Rosstat_GetOrganizationInfo_EP"/>      <with-param name="setEndpointURL" value="webServiceURL_GetRosstatOrganizationInfo"/>      <with-param name="setEndpointURL_Suffix" value=""/>      <with-param name="setQueryParams" value=""/>  </call-template>  <filter regex="200" source="$axis2:HTTP_SC">      <then>          <class description="OutResLoggerJSON" name="ru.rosbank.mediator.LoggerMediatorJSON">              <property name="logLevel" value="INFO"/>              <property name="ReqType" value="OutResponse"/>              <property name="isLogHeader" value="true"/>              <property name="isLogPayload" value="true"/>          </class>          <sequence key="Rosstat_GetOrganizationInfo_MappingOUT_Sequence"/>      </then>      <else>          <class description="OutResLoggerBINARY" name="ru.rosbank.mediator.LoggerMediatorBINARY">              <property name="logLevel" value="INFO"/>              <property name="ReqType" value="OutResponse"/>              <property name="isLogHeader" value="true"/>              <property name="isLogPayload" value="true"/>          </class>          <call-template description="SoapFault" target="Rosstat_SOAPFault_Template">              <with-param name="MessageID" value="{$ctx:ENV_MESSAGE_ID}"/>              <with-param name="ErrorText" value="GetOrganizationInfo returns non success response"/>              <with-param name="Exception" value="{fn:concat('Error: ', $axis2:HTTP_SC, ' - ', $axis2:HTTP_SC_DESC)}"/>          </call-template>      </else>  </filter>  </sequence>

Следующий шаг — MappingOUT — обратная трансформация из JSON в SOAP:

Здесь мы сохраняем в локальные переменные из JSON интересные нам id, type и name и генерируем payload для xml-ки SOAPResponse:

<sequence name="Rosstat_GetOrganizationInfo_MappingOUT_Sequence" onError="Rosstat_FaultSequence" trace="disable" xmlns="http://ws.apache.org/ns/synapse">  <propertyGroup description="Group of properties that extract data from response">      <property expression="json-eval($.[0].id)" name="id" scope="default" type="STRING"/>      <property expression="json-eval($.[0].type)" name="type" scope="default" type="STRING"/>      <property expression="json-eval($.[0].name)" name="name" scope="default" type="STRING"/>          <!-- остальные параметры протокола обмена удалены, для упрощения чтения -->  </propertyGroup>  <payloadFactory description="SOAPResponse" media-type="xml">      <format>          <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">              <soapenv:Body>                  <p:RosstatOrganizationInfoResponse xmlns:p="http://ru.rosbank.servicemix/cd/client">                      <p:id>$1</p:id>                      <p:type>$2</p:type>                      <p:name>$3</p:name>                  </p:RosstatOrganizationInfoResponse>              </soapenv:Body>          </soapenv:Envelope>      </format>      <args>          <arg evaluator="xml" expression="get-property('id')"/>          <arg evaluator="xml" expression="get-property('type')"/>          <arg evaluator="xml" expression="get-property('name')"/>      </args>  </payloadFactory>  <propertyGroup description="removeHeaders">      <property action="remove" name="TRANSPORT_HEADERS" scope="axis2"/>      <property action="remove" name="EXCESS_TRANSPORT_HEADERS" scope="axis2"/>  </propertyGroup>  <propertyGroup description="setHeaders">      <property name="HTTP_SC" scope="axis2" type="STRING" value="200"/>      <property name="HTTP_SC_DESC" scope="axis2" type="STRING" value="OK"/>      <property name="MESSAGE_FORMAT" scope="default" type="STRING" value="soap11"/>      <property name="messageType" scope="axis2" type="STRING" value="text/xml"/>      <property name="ContentType" scope="axis2" type="STRING" value="text/xml"/>      <property name="Content-Type" scope="transport" type="STRING" value="text/xml;charset=UTF-8"/>      <property name="RESPONSE" scope="default" type="STRING" value="true"/>  </propertyGroup>  </sequence>

Конечно, удаляем все ненужные транспортные заголовки из REST API, как и в прошлом случае.

Обязательно нужно сделать и последовательность для HealthCheck — ​​проверку готовности сервиса принимать траффик (Readness Probe). Он пригодится, когда мы будем деплоить всё в Kubernetes или OpenShift.

<sequence name="Rosstat_HealthRequest_Sequence" onError="Rosstat_FaultSequence" trace="disable" xmlns="http://ws.apache.org/ns/synapse">  <propertyGroup description="removeHeaders">      <property action="remove" name="TRANSPORT_HEADERS" scope="axis2"/>      <property action="remove" name="EXCESS_TRANSPORT_HEADERS" scope="axis2"/>  </propertyGroup>  <payloadFactory description="SOAPResponse" media-type="xml">      <format>          <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">              <soapenv:Body>                  <p:HealthResponse xmlns:p="http://ru.rosbank.servicemix/cd/client">                      <p:status>OK</p:status>                  </p:HealthResponse>              </soapenv:Body>          </soapenv:Envelope>      </format>      <args/>  </payloadFactory>  <propertyGroup description="setHeaders">      <property name="HTTP_SC" scope="axis2" type="STRING" value="200"/>      <property name="HTTP_SC_DESC" scope="axis2" type="STRING" value="OK"/>      <property name="MESSAGE_FORMAT" scope="default" type="STRING" value="soap11"/>      <property name="messageType" scope="axis2" type="STRING" value="text/xml"/>      <property name="ContentType" scope="axis2" type="STRING" value="text/xml"/>      <property name="Content-Type" scope="transport" type="STRING" value="text/xml;charset=UTF-8"/>      <property name="RESPONSE" scope="default" type="STRING" value="true"/>  </propertyGroup>  <class description="InResLoggerSOAP" name="ru.rosbank.mediator.LoggerMediatorSOAP">      <property name="logLevel" value="INFO"/>      <property name="ReqType" value="InResponse"/>      <property name="isLogHeader" value="true"/>      <property name="isLogPayload" value="true"/>  </class>  </sequence>

Далее создадим endpoint для вызова внешних сервисов. Здесь всё так же, как и с REST API.

<endpoint name="Rosstat_GetOrganizationInfo_EP" xmlns="http://ws.apache.org/ns/synapse">  <http method="post" uri-template="{uri.var.endpointURL_FullAddress}">      <timeout>          <duration>40000</duration>          <responseAction>fault</responseAction>      </timeout>      <suspendOnFailure>          <errorCodes>101500,101501,101506,101507,101508</errorCodes>          <initialDuration>1000</initialDuration>          <progressionFactor>2.0</progressionFactor>          <maximumDuration>60000</maximumDuration>      </suspendOnFailure>      <markForSuspension>          <errorCodes>101503,101504,101505</errorCodes>          <retriesBeforeSuspension>3</retriesBeforeSuspension>          <retryDelay>100</retryDelay>      </markForSuspension>  </http>  </endpoint>

Добавляем WSDL-файл и XSD-схемы

В модуле RosstatServiceRegistryResources (в нашем примере) выбираем New – RegistryResource и в появившемся окне — From existing template.

 Далее выставляем параметры. 

ResourceName: RosstatOrganizationInfo (указываем имя файла WSDL без расширения) 
ArtifactName: RosstatOrganizationInfoWSDL (то же самое, что и для ResourceName, только добавляем в конце суффикс WSDL)
Template: выбираем из списка значение WSDL File
Registry: выбираем из списка значение conf
RegistryPath: resources/rosstat/wsdl

Аналогичным образом добавляем XSD-схемы.

ResourceName: RosstatOrganizationInfo (указываем имя файла XSD без расширения)
ArtifactName: RosstatOrganizationInfoXSD (то же самое, что и для ResourceName, только добавляем в конце суффикс XSD)
Template: выбираем из списка значение XSD File
Registry: выбираем из списка значение conf
RegistryPath: resources/rosstat/wsdl

Создаем ProxyService

С SOAP и другими протоколами, кроме REST API, используется ProxyService. Сделаем новый ProxyService, используя ранее созданные Template, Sequence, Endpoint.

Выбираем тип Custom Proxy и указываем транспортные протоколы http и https: 

 В режиме Design ProxyService будет выглядеть вот так: 

Атрибут name у корневого элемента proxy является именем SOAP-сервиса. Значение должно совпадать с тем, что будет в URL после /services/: https://localhost:8253/services/RosstatService?wsdl. Мы также добавили в код валидацию запроса по XSD:

<proxy name="RosstatService" startOnLoad="true" transports="http https" xmlns="http://ws.apache.org/ns/synapse">  <target>      <inSequence>          <sequence key="Rosstat_InboundSequence"/>          <validate cache-schema="true">              <schema key="conf:resources/rosstat/wsdl/RosstatOrganizationInfo.xsd"/>              <on-fail>                  <sequence key="Rosstat_FaultSequence"/>              </on-fail>          </validate>          <switch source="$ctx:ENV_METHOD_NAME">              <case regex="RosstatOrganizationInfoRequest">                  <sequence key="Rosstat_GetOrganizationInfo_Sequence"/>              </case>              <case regex="HealthRequest">                  <sequence key="Rosstat_HealthRequest_Sequence"/>              </case>              <default>                  <sequence key="Rosstat_UnsupportedService_Sequence"/>              </default>          </switch>          <sequence key="Rosstat_OutboundSequence"/>          <respond/>      </inSequence>      <outSequence/>      <faultSequence>          <sequence key="Rosstat_FaultSequence"/>      </faultSequence>  </target>  <publishWSDL key="conf:resources/rosstat/wsdl/RosstatOrganizationInfo.wsdl" preservePolicy="true">      <resource key="conf:resources/rosstat/wsdl/RosstatOrganizationInfo.xsd" location="RosstatOrganizationInfo.xsd"/>  </publishWSDL>  <parameter name="disableREST">true</parameter>  <parameter name="disableSOAP12">true</parameter>  </proxy>

В блоке «publishWSDL» нужно обязательно указать ссылки на WSDL-файл и XSD-схемы (если их несколько), которые были добавлены в проект на предыдущем шаге. Это необходимо как раз для валидации и получения корректных файлов WSDL/XSD через адрес https://localhost:8253/services/RosstatService?wsdl.  

Если сервис должен работать по SOAP 1.1/1.2, необходимо отключить REST и ненужную версию протокола SOAP.

Для SOAP 1.1:

<parameter name="disableREST">true</parameter> <parameter name="disableSOAP12">true</parameter> 

Для SOAP 1.2:

<parameter name="disableREST">true</parameter>  <parameter name="disableSOAP11">true</parameter>

Собираем сервис

Открывает pom-файл в модуле RosstatServiceCompositeExporter и выбираем все созданные артефакты в модулях RosstatServiceConfig и RosstatServiceRegistryResources:

Сборка сервиса через Maven организована так же, как и в случае с REST API.

Дальнейшие действия зависят от конкретного проекта. Как я указывал в прошлой статье, мы пишем интеграционные тесты с использованием Postman и заглушки для BackendService с Wiremock. 

Если у вас появились вопросы по разработке на WSO2, буду рад ответить на них в комментариях. Мы планируем продолжать серию публикаций по этой платформе, так что подписывайтесь, если интересно, и пишите, что еще хотели бы о ней узнать.


ссылка на оригинал статьи https://habr.com/ru/company/rosbank/blog/648919/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *