@Singleton
@WebService(
portName = "CalculatorPort",
serviceName = "CalculatorService",
targetNamespace = "http://superbiz.org/wsdl",
endpointInterface = "org.superbiz.calculator.wsh.CalculatorWs")
@HandlerChain(file = "handlers.xml")
public class Calculator implements CalculatorWs {
public int sum(int add1, int add2) {
return add1 + add2;
}
public int multiply(int mul1, int mul2) {
return mul1 * mul2;
}
}
Mantenedores @WebService com @HandlerChain
Neste exemplo nós vemos um básico componente @WebService JAX-WS usar uma
cadeia de mantenedores para alterar mensagens SOAP enviadas e recebidas.
Mantenedores SOAP são parecidos com Filtros Servlet ou Interceptadores EJB/CDI.
Em alto nível, as etapas envolvidas são:
-
Crie mantenedores implementando
jakarta.xml.ws.handler.soap.SOAPHandler -
Declare e ordene-os em um arquivo xml via
<handler-chain> -
Associe o arquivo xml com um componente
@WebServicevia@HandlerChain
O @HandlerChain
Primeiro, começaremos com nosso simples bean @WebService, chamado
Calculator, que é anotado com @HandlerChain
Aqui vemos @HandlerChain apontando para um arquivo chamado handlers.xml.
Esse arquivo pode ser chamado de qualquer coisa, mas deve estar no mesmo jar e
pacote java como nosso componente Calculator.
O arquivo <handler-chains>
Nosso serviço Calculator está no pacote org.superbiz.calculator.wsh,
o que significa que o arquivo xml da cadeia de mantenedores
deve estar em org/superbiz/calculator/wsh/handlers.xml em nosso
classpath do aplicativo ou o arquivo não será encontrado e nenhum mantenedor
será usado.
No maven, conseguimos isso colocando nosso handlers.xml em
src/main/resources igual a:
-
src/main/resources/org/superbiz/calculator/wsh/handlers.xml
Com este arquivo nós declaramos e ordenamos nossa cadeia mantenedora.
<?xml version="1.0" encoding="UTF-8"?>
<handler-chains xmlns="http://java.sun.com/xml/ns/javaee">
<handler-chain>
<handler>
<handler-name>org.superbiz.calculator.wsh.Inflate</handler-name>
<handler-class>org.superbiz.calculator.wsh.Inflate</handler-class>
</handler>
<handler>
<handler-name>org.superbiz.calculator.wsh.Increment</handler-name>
<handler-class>org.superbiz.calculator.wsh.Increment</handler-class>
</handler>
</handler-chain>
</handler-chains>
A ordem como você pode suspeitar é:
-
Inflate -
Increment
A implementação SOAPHandler
Nosso manipulador Inflate tem o trabalho de monitorar retornos para as
operações 'sum' e 'multiply' e fazê-las 1000 vezes melhores.
A manipulação da mensagem é feita andando pelo SOAPBody e
editando os nódulos. O método handleMessage é invocado para ambos,
requisições e retornos, por isso é importante para verificar o SOAPBody
antes de tentar navegar os nódulos.
import org.w3c.dom.Node;
import javax.xml.namespace.QName;
import jakarta.xml.soap.SOAPBody;
import jakarta.xml.soap.SOAPException;
import jakarta.xml.soap.SOAPMessage;
import jakarta.xml.ws.handler.MessageContext;
import jakarta.xml.ws.handler.soap.SOAPHandler;
import jakarta.xml.ws.handler.soap.SOAPMessageContext;
import java.util.Collections;
import java.util.Set;
public class Inflate implements SOAPHandler<SOAPMessageContext> {
public boolean handleMessage(SOAPMessageContext mc) {
try {
final SOAPMessage message = mc.getMessage();
final SOAPBody body = message.getSOAPBody();
final String localName = body.getFirstChild().getLocalName();
if ("sumResponse".equals(localName) || "multiplyResponse".equals(localName)) {
final Node responseNode = body.getFirstChild();
final Node returnNode = responseNode.getFirstChild();
final Node intNode = returnNode.getFirstChild();
final int value = new Integer(intNode.getNodeValue());
intNode.setNodeValue(Integer.toString(value * 1000));
}
return true;
} catch (SOAPException e) {
return false;
}
}
public Set<QName> getHeaders() {
return Collections.emptySet();
}
public void close(MessageContext mc) {
}
public boolean handleFault(SOAPMessageContext mc) {
return true;
}
}
O mantenedor Increment é identico no código e portanto não é mostrado.
Ao invés de multiplicar por 1000, este simplesmente adiciona 1.
O Caso de Teste
Nós usamos a API JAX-WS para criar um cliente Java para o nosso serviço web
Calculator e o usamos para chamar as operações` sum` e multiply.
Observemos o uso inteligente da matemática, para afirmar tanto a existência e
a ordem de nossos mantenedores. Se 'Inflate' e 'Increment' forem invertidos,
as respostas seriam 11000 e 13000, respectivamente.
@RunWith(Arquillian.class)
public class CalculatorTest {
@ArquillianResource
private URL base;
@Deployment(testable = false)
public static WebArchive war() {
return ShrinkWrap.create(WebArchive.class, "webservice-handlerchain.war")
.addClasses(Calculator.class, CalculatorWs.class, Inflate.class, Increment.class)
.addAsResource("org/superbiz/calculator/wsh/handlers.xml");
}
@Test
public void testCalculatorViaWsInterface() throws Exception {
final Service calculatorService = Service.create(
new URL(base.toExternalForm() + "webservices/Calculator?wsdl"),
new QName("http://superbiz.org/wsdl", "CalculatorService"));
assertNotNull(calculatorService);
final CalculatorWs calculator = calculatorService.getPort(CalculatorWs.class);
// we expect our answers to come back 1000 times better, plus one!
assertEquals(10001, calculator.sum(4, 6));
assertEquals(12001, calculator.multiply(3, 4));
}
}
Executando o exemplo
Simplesmente execute mvn clean install e você verá resultado semelhante o seguinte:
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running org.superbiz.calculator.wsh.CalculatorTest
INFO: Starting Servlet engine: [Apache Tomcat/11.0.25]
INFO: Version: 10.3.0-SNAPSHOT
INFO: ------------------------- localhost -> /webservice-handlerchain
INFO: Configuring enterprise application: /path/to/examples/webservice-handlerchain/target/tomee-embedded/0/webservice-handlerchain
INFO: Auto-deploying ejb Calculator: EjbDeployment(deployment-id=Calculator)
INFO: Created Ejb(deployment-id=Calculator, ejb-name=Calculator, container=Default Singleton Container)
INFO: Started Ejb(deployment-id=Calculator, ejb-name=Calculator, container=Default Singleton Container)
INFO: Webservice(wsdl=http://localhost:53503/webservice-handlerchain/webservices/Calculator, qname={http://superbiz.org/wsdl}CalculatorService) --> Ejb(id=Calculator)
INFO: Deployed Application(path=/path/to/examples/webservice-handlerchain/target/tomee-embedded/0/webservice-handlerchain)
INFO: Creating Service {http://superbiz.org/wsdl}CalculatorService from WSDL: http://localhost:53503/webservice-handlerchain/webservices/Calculator?wsdl
INFO: Undeploying app: /path/to/examples/webservice-handlerchain/target/tomee-embedded/0/webservice-handlerchain
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 2.124 s -- in org.superbiz.calculator.wsh.CalculatorTest
Results :
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
Inspecionando as mensagens
A execução acima geraria as seguintes mensagens.
Calculator wsdl
<?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="multiply" type="tns:multiply"/>
<xsd:complexType name="multiply">
<xsd:sequence>
<xsd:element name="arg0" type="xsd:int"/>
<xsd:element name="arg1" type="xsd:int"/>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="multiplyResponse" type="tns:multiplyResponse"/>
<xsd:complexType name="multiplyResponse">
<xsd:sequence>
<xsd:element name="return" type="xsd:int"/>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="sum" type="tns:sum"/>
<xsd:complexType name="sum">
<xsd:sequence>
<xsd:element name="arg0" type="xsd:int"/>
<xsd:element name="arg1" type="xsd:int"/>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="sumResponse" type="tns:sumResponse"/>
<xsd:complexType name="sumResponse">
<xsd:sequence>
<xsd:element name="return" type="xsd:int"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
</wsdl:types>
<wsdl:message name="multiplyResponse">
<wsdl:part element="tns:multiplyResponse" name="parameters">
</wsdl:part>
</wsdl:message>
<wsdl:message name="sumResponse">
<wsdl:part element="tns:sumResponse" name="parameters">
</wsdl:part>
</wsdl:message>
<wsdl:message name="sum">
<wsdl:part element="tns:sum" name="parameters">
</wsdl:part>
</wsdl:message>
<wsdl:message name="multiply">
<wsdl:part element="tns:multiply" name="parameters">
</wsdl:part>
</wsdl:message>
<wsdl:portType name="CalculatorWs">
<wsdl:operation name="multiply">
<wsdl:input message="tns:multiply" name="multiply">
</wsdl:input>
<wsdl:output message="tns:multiplyResponse" name="multiplyResponse">
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="sum">
<wsdl:input message="tns:sum" name="sum">
</wsdl:input>
<wsdl:output message="tns:sumResponse" name="sumResponse">
</wsdl:output>
</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="multiply">
<soap:operation soapAction="" style="document"/>
<wsdl:input name="multiply">
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output name="multiplyResponse">
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="sum">
<soap:operation soapAction="" style="document"/>
<wsdl:input name="sum">
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output name="sumResponse">
<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:8080/webservice-handlerchain/webservices/Calculator"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
SOAP sum e sumResponse
Requisição:
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns1:sum xmlns:ns1="http://superbiz.org/wsdl">
<arg0>4</arg0>
<arg1>6</arg1>
</ns1:sum>
</soap:Body>
</soap:Envelope>
Retorno:
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns1:sumResponse xmlns:ns1="http://superbiz.org/wsdl">
<return>10001</return>
</ns1:sumResponse>
</soap:Body>
</soap:Envelope>
SOAP multiply e multiplyResponse
Requisição:
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns1:multiply xmlns:ns1="http://superbiz.org/wsdl">
<arg0>3</arg0>
<arg1>4</arg1>
</ns1:multiply>
</soap:Body>
</soap:Envelope>
Retorno:
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns1:multiplyResponse xmlns:ns1="http://superbiz.org/wsdl">
<return>12001</return>
</ns1:multiplyResponse>
</soap:Body>
</soap:Envelope>