Labs SD >

Web Services: Contract-First

Objetivos

Web Services

Um serviço é uma funcionalidade de um sistema informático que pode ser invocada remotamente através da rede, usando protocolos de comunicação da World Wide Web, nomeadamente, HTTP. A tecnologia permite também a utilização de outros transportes.

WSDL

Os Web Services têm uma linguagem própria para descrever o seu contrato com os clientes.
A WSDL permite especificar a interface funcional, chamada port type, que define as operações com entradas, saídas e erros. A WSDL define também a interface concreta, com escolhas de tecnologias concretas a usar. Cada escolha é representada num binding.

Exemplo de um contrato WSDL:

Web Services em Java

A plataforma Java inclui uma implementação dos Web Services. A biblioteca chama-se JAX-WS, que significa Java API for XML Web Services.

É possível implementar Web Services partindo de um contrato WSDL existente.
Esta abordagem ao desenvolvimento de serviços é chamada contract-first.

A ferramenta wsimport permite gerar código a partir do contrato WSDL, para clientes e para servidores.

A JAX-WS também permite intercetar as mensagens SOAP que são enviadas ou recebidas pelo serviço, através de objetos chamados handlers.

Exemplo Ping Web Service:

Nota: as pastas que contêm o código não devem ter espaços nem caracteres acentuados no seu caminho.

JUnit Integration Tests (IT)

Os testes de integração de Web Services permitem verificar se o contrato das operações remotas definidas no WSDL está a ser respeitado por um servidor.

Os IT são definidos no cliente (ws-cli) e fazem invocações remotas ao servidor (ws). Assume-se que todos os servidores foram lançados antes de correr os testes de integração.

 


Informação adicional sobre Web Services

 


Exercício

O ponto de partida do exercício é um Web Service de um fornecedor de produtos e um cliente para o mesmo.
O código fornecido inclui um servidor incompleto (supplier-ws UML) e um cliente incompleto (supplier-ws-cli UML).

  1. As classes de domínio da aplicação já estão implementadas.
    1. Consulte o pacote domain do servidor.
    2. Identifique o Domain Root e as restantes entidades representadas nas classes.
    3. Analise os mecanismos de sincronização que são utilizados para garantir que as classes podem ser chamadas corretamente por múltiplas tarefas (threads).
  2. De seguida, consultar o contrato WSDL do serviço a implementar:
  3. Vamos gerar código Java a partir do WSDL. O Maven está configurado para chamar a ferramenta wsimport.
    1. Copie o ficheiro WSDL do serviço a implementar para a pasta src/main/resources do servidor.
    2. Vamos agora gerar o código Java do servidor a partir do WSDL:
      cd supplier-ws
    3. mvn generate-sources
      Caso o WSDL esteja bem formado e válido, a ferramenta wsimport gera vários ficheiros que suportam o web service. Entre eles, estarão as classes para os tipos complexos usados como parâmetros e a interface Java que define o Web Service.
    4. Faça refresh no Eclipse e consulte as classes geradas na pasta: target/generated-sources/wsimport.
      Em especial, consulte a classe ...Service, e descubra a interface Java ...PortType que foi gerada a partir do WSDL.
  4. Vamos agora concretizar o serviço.
    1. Consulte a classe de implementação do serviço ...PortImpl, que deverá implementar a interface Java gerada.
    2. Deverá associar a classe PortImpl ao WSDL através da anotação @WebService com os seguintes atributos: endpoint interface (nome do tipo Java do PortType), wsdlLocation (nome do ficheiro WSDL), name (definido no WSDL), portName (WSDL), targetNamespace (WSDL) e serviceName (WSDL).
    3. Além da anotação, todos os métodos listados na interface PortType devem ser implementados na classe do serviço.

      Cada método é uma operação do Web Service, com entradas, saídas e excepções.
      Para cada operação, confira se está corretamente implementada.
      Adicione a anotação @Override antes de cada método de operação, para que o compilador confirme que está a implementar corretamente o método definido na interface.
      Note que as operações searchProducts e buyProducts não estão implementadas. Para já vamos compilar e executar o servidor sem estas operações estarem concluídas.
  5. Executar o servidor:
    1. mvn compile exec:java
      O nome da classe a executar e os argumentos estão definidos no pom.xml
      O servidor deve executar sem erros, disponibilizando o endpoint address.
    2. Confirmar que o servidor está à espera de pedidos no endereço:

Vamos agora usar o cliente supplier-ws-cli para testar o servidor.

  1. Vamos gerar o código Java para invocação do serviço.
    1. Consultar o pom.xml do cliente para confirmar que o WSDL está a ser corretamente referenciado (propriedades wsdl.directory e wsdl.filename)
    2. cd supplier-ws-cli
    3. mvn generate-sources
      As classes são geradas na pasta: target/generated-sources/wsimport.
  2. Vamos fazer uma chamada simples, correndo a aplicação cliente.
  3. Depois deste teste pontual, vamos correr os testes de integração já existentes.

Vamos agora analisar, em detalhe, as mensagens SOAP usadas para comunicação entre cliente e servidor. Vamos ativar um handler no servidor (classe PrintSOAPHandler) que vai intercetar e imprimir as mensagens SOAP para a consola.

  1. Na pasta src/main/resources já se encontra um ficheiro supplier-ws_handler-chain.xml com a configuração da cadeia de interceção.
  2. Para ativarmos o handler, temos que adicionar a seguinte anotação ao PortImpl:
    @HandlerChain(file = "/supplier-ws_handler-chain.xml")
  3. Recompilar e relançar o servidor.
    • cd supplier-ws
    • mvn compile exec:java
  4. Usar o cliente para chamar o ping.
    • cd supplier-ws-cli
    • mvn compile exec:java
  5. Agora, ao receber mensagens, estas serão capturadas e impressas para a consola do servidor.
    1. Qual é a etiqueta principal da mensagem SOAP?
    2. Onde são transportados os argumentos das operações? E os resultados?

O que falta fazer?


© Docentes de Sistemas Distribuídos, Dep. Eng. Informática, Técnico Lisboa