Статьи

Использование JAXB и JAX-WS для обслуживания с пользовательскими заголовками


С момента появления JAX-WS в Java EE создание веб-сервисов SOAP никогда не было таким простым (по сравнению с Spring WS).
Всего несколько аннотаций, и все готово. Недостатком всего этого является то, что он всегда исходит из контракта или подхода Java. Хотя во многих средах это так, ситуации бывают, когда это смешанный случай.

Совсем недавно я столкнулся со смешанным делом. Нужно было заменить существующую службу, у которой не было никаких WSDL, но XSD для полезной нагрузки был там. Ниже приведены шаги, которые я выполнил для реализации новой службы из существующих XSD и включенных входящих и исходящих заголовков.

Генерация ObjectFactories из предоставленных XSD-файлов в maven проста, просто добавьте следующий фрагмент в файл pom maven:

<plugin>
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>jaxb2-maven-plugin</artifactId>
  <version>1.6</version>
  <executions>
    <execution>
      <id>xjc</id>
      <goals>
        <goal>xjc</goal>
      </goals>
    </execution>
  </executions>
  <configuration>
    <bindingFiles>
      bindings.xjb
    </bindingFiles>
  </configuration>
</plugin>

Это все, что нужно для создания файлов JAXB. Указанный мной файл привязок позволяет вам настраивать сгенерированные классы. Я склонен конвертировать xsd: DateTime в JodaTime, но это только я.

Далее определение сервисов JAX-WS. В Интернете доступно множество руководств для начала работы с JAX-WS. Нет смысла в этом разбираться. Я обнаружил, что информация о работе с заголовками неоднозначна.

Все предоставленные решения помогут получить заголовки в сообщении. Чего вы не находите, так это решения, использующего аннотацию @WebParam в списке аргументов веб-службы. У аннотации есть два важных поля для поддержки заголовка; заголовок и режим .

Установка поля заголовка в true добавит это к заголовочной части сообщения мыла. флаг режима допускает следующие значения:

  • IN
    Inbound
  • OUT
    Outbound
  • INOUT
    в и исходящих.

Первые два просты в использовании. последнее, INOUT имеет немного больше.

При использовании значения WebParam.Mode.INOUT изменения значительны, так как используемый вами контейнер не может генерировать файлы WSDL и XSD. Ошибка, которую вы получаете, неоднозначна. Конечный результат ваш WSDL не генерируется, следовательно, сервис недоступен. Ключ при использовании режима INOUT — это универсальный класс javax.xml.ws.Holder <T> . Когда параметр находится внутри этого типа. WSDL генерируется правильно.

Результирующий метод @WebMethod:

 @WebMethod(
        action = "ServiceName",
        operationName = "operation"
    )
    public MyResponse operation(
        @WebParam(mode = WebParam.Mode.INOUT, header = true, name = "JaxbHeader",
                  targetNamespace = "http://www.elucidator.nl/header/v1.0")
        final Holder headerHolder,
        @WebParam(mode = WebParam.Mode.IN, name = "data") final JaxbPayload payload)
        throws MyServiceException
  {
    //SNIP
    if (headerHolder.value.flag) {
       headerHolder.value.field = "SomeValue";
    return responseObject;
  }

Доступ к значениям в объекте заголовка прямой. при изменении значений ответ содержит измененные значения. Благодаря этому решению нет необходимости писать собственные  реализации SOAPHandler для заголовков.

Сгенерированный WSDL будет:

<definitions xmlns:ns1="..." xmlns:tns="..." 
     xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
     xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 
     xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" 
     name="MyService" 
     targetNamespace="..." 
     xmlns="http://schemas.xmlsoap.org/wsdl/">
    <types>
       //SNIP
    </types>
    <message name="operation">
        <part name="parameters" element="tns:operation"/>
        <part name="jaxbHeader" element="ns1:JaxbHeader"/>
    </message>
    <message name="operationResponse">
        <part name="result" element="tns:operationResponse"/>
        <part name="JaxbHeader" element="ns1:JaxbHeader"/>
    </message>
    <portType name="ServiceName">
        <operation name="insert" parameterOrder="parameters JaxbHeader">
            <input message="tns:operation" wsam:Action="operation"/>
            <output message="tns:operationResponse" wsam:Action="http://www.elucidator.nl/ws/v1.0/operationResponse"/>
        </operation>
    </portType>
    <binding name="ServiceNameBinding" type="tns:ServiceName">
        <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
        <operation name="insert">
            <soap:operation soapAction="operation"/>
            <input>
                <soap:body parts="parameters" use="literal"/>
                <soap:header message="tns:operation" part="JaxbHeader" use="literal"/>
            </input>
            <output>
                <soap:body parts="result" use="literal"/>
                <soap:header message="tns:operationResponse" part="JaxbHeader" use="literal"/>
            </output>
        </operation>
    </binding>
    <service name="ServiceName">
        <port name="ServiceNamePort" binding="tns:ServicePortBinding">
            <soap:address location="http://localhost:9081/Service"/>
        </port>
    </service>
</definitions>

Как видите, прекрасно сгенерированный WSDL, который содержит информацию о ожидаемых и возвращаемых заголовках.

Однако у этого решения есть один небольшой недостаток. Когда выдается исключение, у вас больше нет доступа к заголовкам. У меня есть решение для этого, реализация обработчика, который перехватывает запрос, сохраняет заголовок и изменяет ответ на ошибку в методе handleFault . Но это тема для другого поста.

 

Оригинал можно найти на: Elucidator