:index-group: Web Services :jbake-type: page :jbake-status:
status=published = parâmetros @WebService OUT via javax.xml.ws.Holder

Com SOAP é possivel retornar multiplos valores em uma única requisição.
Isto é impossível em Java pois um método pode retornar somente um objeto.

JAX-WS resolve esse problema com o conceito de Holders. Um
`javax.xml.ws.Holder` é um simples wrapper objeto que pode ser passado para   
o método `@WebService` como um parâmetro.  A aplicação atribui o valor 
do mantenedor durante a requisição e o servidor enviará valor de volta 
como um parâmetro OUT.

== Usando @WebParam e javax.xml.ws.Holder

A anotação `@WebParam` nos permite declarar os Holders `soma` e `multiplicação` 
como parâmetros `WebParam.Mode.OUT`. Como mencionado, esses mantenedores 
são simplesmente cestas vázias, a aplicação pode preencher com dados para poder  
enviar para o cliente. O servidor irá passar então, em não inicializado.

[source,java]
----
@Stateless
@WebService(
        portName = "CalculatorPort",
        serviceName = "CalculatorService",
        targetNamespace = "http://superbiz.org/wsdl",
        endpointInterface = "org.superbiz.ws.out.CalculatorWs")
public class Calculator implements CalculatorWs {

    public void sumAndMultiply(int a, int b,
                               @WebParam(name = "sum", mode = WebParam.Mode.OUT) Holder<Integer> sum,
                               @WebParam(name = "multiply", mode = WebParam.Mode.OUT) Holder<Integer> multiply) {
        sum.value = a + b;
        multiply.value = a * b;
    }
}
----

Se os Holders foram especificados como parâmetros `WebParam.Mode.INOUT`, então o
cliente consegueria utilizá-los para enviar dados e a aplicação também. A 
instância `Holder` seria então inicializada com os dados que da 
requisição do cliente. A aplicação poderia verificar os dados antes eventualmente
sobrescrevendo-os com os valores de resposta.

== O WSDL

O componente JAX-WS  `@WebService` acima resulta no seguinte WSDL
que será criado automaticamente. Aviso o tipo complexo `sumAndMultiplyResponse`
retorna dois elementos. Estes correspondem as declarações `@WebParam` 
e nossos dois parâmetros `Holder<Integer>`.

[source,xml]
----
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
                  name="CalculatorService"
                  targetNamespace="http://superbiz.org/wsdl"
                  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
                  xmlns:tns="http://superbiz.org/wsdl"
                  xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <wsdl:types>
    <xsd:schema attributeFormDefault="unqualified" elementFormDefault="unqualified"
                targetNamespace="http://superbiz.org/wsdl"
                xmlns:tns="http://superbiz.org/wsdl"
                xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <xsd:element name="sumAndMultiply" type="tns:sumAndMultiply"/>
      <xsd:complexType name="sumAndMultiply">
        <xsd:sequence>
          <xsd:element name="arg0" type="xsd:int"/>
          <xsd:element name="arg1" type="xsd:int"/>
        </xsd:sequence>
      </xsd:complexType>
      <xsd:element name="sumAndMultiplyResponse" type="tns:sumAndMultiplyResponse"/>
      <xsd:complexType name="sumAndMultiplyResponse">
        <xsd:sequence>
          <xsd:element minOccurs="0" name="sum" type="xsd:int"/>
          <xsd:element minOccurs="0" name="multiply" type="xsd:int"/>
        </xsd:sequence>
      </xsd:complexType>
    </xsd:schema>
  </wsdl:types>
  <wsdl:message name="sumAndMultiplyResponse">
    <wsdl:part element="tns:sumAndMultiplyResponse" name="parameters"/>
  </wsdl:message>
  <wsdl:message name="sumAndMultiply">
    <wsdl:part element="tns:sumAndMultiply" name="parameters"/>
  </wsdl:message>
  <wsdl:portType name="CalculatorWs">
    <wsdl:operation name="sumAndMultiply">
      <wsdl:input message="tns:sumAndMultiply" name="sumAndMultiply"/>
      <wsdl:output message="tns:sumAndMultiplyResponse" name="sumAndMultiplyResponse"/>
    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding name="CalculatorServiceSoapBinding" type="tns:CalculatorWs">
    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="sumAndMultiply">
      <soap:operation soapAction="" style="document"/>
      <wsdl:input name="sumAndMultiply">
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output name="sumAndMultiplyResponse">
        <soap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="CalculatorService">
    <wsdl:port binding="tns:CalculatorServiceSoapBinding" name="CalculatorPort">
      <soap:address location="http://127.0.0.1:4204/Calculator?wsdl"/>
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>
----

== Testando os parâmetros OUT

Aqui nós vemos um cliente JAX-WS executando a operação `sumAndMultiply`.
Duas instâncias vázias do `Holder` são criadas e passadas como parâmetros.
Os dados da `sumAndMultiplyResponse` são colocados na instância `Holder`
e então ficam disponíveis para o cliente depois da operação completa.

Os mantenedores não são realmente enviados na requisição, a menos que eles 
estejam configurados como parâmetros INOUT via WebParam.Mode.INOUT em `@WebParam`

[source,java]
----
import org.junit.BeforeClass;
import org.junit.Test;

import javax.ejb.embeddable.EJBContainer;
import javax.xml.namespace.QName;
import javax.xml.ws.Holder;
import javax.xml.ws.Service;
import java.net.URL;
import java.util.Properties;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

public class CalculatorTest {

    @BeforeClass
    public static void setUp() throws Exception {
        Properties properties = new Properties();
        properties.setProperty("openejb.embedded.remotable", "true");
        //properties.setProperty("httpejbd.print", "true");
        //properties.setProperty("httpejbd.indent.xml", "true");
        EJBContainer.createEJBContainer(properties);
    }

    @Test
    public void outParams() throws Exception {
        final Service calculatorService = Service.create(
                new URL("http://127.0.0.1:4204/Calculator?wsdl"),
                new QName("http://superbiz.org/wsdl", "CalculatorService"));

        assertNotNull(calculatorService);

        final CalculatorWs calculator = calculatorService.getPort(CalculatorWs.class);

        final Holder<Integer> sum = new Holder<Integer>();
        final Holder<Integer> multiply = new Holder<Integer>();

        calculator.sumAndMultiply(4, 6, sum, multiply);

        assertEquals(10, (int) sum.value);
        assertEquals(24, (int) multiply.value);
    }
}
----

== Analisando as mensagens

A execução acima resulta na seguinte mensagem SOAP.

=== requisição cliente SOAP sumAndMultiply  

[source,xml]
----
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <ns1:sumAndMultiply xmlns:ns1="http://superbiz.org/wsdl">
      <arg0>4</arg0>
      <arg1>6</arg1>
    </ns1:sumAndMultiply>
  </soap:Body>
</soap:Envelope>
----

=== resposta do servidor SOAP sumAndMultiplyResponse 

[source,xml]
----
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <ns1:sumAndMultiplyResponse xmlns:ns1="http://superbiz.org/wsdl">
      <sum>10</sum>
      <multiply>24</multiply>
    </ns1:sumAndMultiplyResponse>
  </soap:Body>
</soap:Envelope>
----
