Labs SD >

Web Services II: UDDI

Objetivos

Projeto ForkExec:

UDDI

Para a publicação e pesquisa de Web Services usa-se um servidor de nomes que implementa a norma UDDI (Universal Description, Discovery and Integration).

Mais informação: UDDI

JAX-R

Para comunicar com servidores UDDI, existe a biblioteca JAX-R (Java API for XML Registries), que permite publicar, pesquisar e eliminar registos de Web Services.

O esquema de dados do UDDI é consideravelmente mais rico do que o habitual num servidor de nomes, com diversas entidades e relações, que permitem guardar informação de negócio sobre a organização e os seus serviços. Como consequência, o JAX-R é uma biblioteca verbosa, que obriga a escrever muitas linhas de código para realizar as tarefas mais habituais de registo e de pesquisa.

Mais informação: JAX-R

UDDI Naming

Para tornar a utilização do UDDI mais simples foi criada a biblioteca UDDINaming que reduziu o esquema de dados para suportar registos simplificados com apenas: 1 organização, 1 serviço e 1 implementação.
Esta biblioteca torna o registo e pesquisa de serviços mais sucinto. O código fonte está disponível para consulta e modificação.

Mais informação:

 


Exemplo

O exemplo seguinte é um Web Service que se regista no UDDI:

Seguem-se instruções detalhadas para construir e executar o exemplo.

 

jUDDI (Java UDDI)

  1. O servidor de nomes a utilizar é o jUDDI alojado na RNL.
  2. Para que a configuração seja feita para todos os exemplos, pode-se criar um perfil Maven que sobrepõe o valor da propriedade para todos os projetos do utilizador. Para isso, criar ou editar o ficheiro settings.xml na pasta .m2 da home do utilizador.

UDDINaming

  1. Obter o código da biblioteca UDDINaming:
  2. Instalar o módulo no repositório Maven local:

Servidor JAX-WS

  1. Construir e executar o servidor:
  2. Para confirmar que o servidor está a funcionar e à espera de pedidos, consultar o contrato que é gerado automaticamente, através dos seguintes endereços:
  3. Este exemplo usa a abordagem de desenvolvimento implementation-first, que gera o WSDL e XSD necessários.

Cliente JAX-WS

  1. Construir o cliente:
  2. Executar o cliente:

Resumindo:
primeiro foi configurado o servidor de nomes jUDDI da RNL.
Depois foi instalada a biblioteca UDDINaming no repositório Maven local, que testa também o funcionamento do servidor jUDDI.
Em seguida, foi construído e iniciado o servidor, que se regista no jUDDI e fica à espera de pedidos no endpoint address.
Finalmente, o cliente obtém o WSDL a partir do servidor e gera o código de invocação que permite depois fazer invocações remotas.

Visão global do exemplo Hello World UML

 


Exercício

Desenvolvimento do Projeto ForkExec

O ponto de partida é o projeto base.
Caso já tenha o repositório de GitHub criado (confirme junto do professor), poderá também obter o código base a partir do GitHub:
git clone https://github.com/tecnico-distsys/CXX-ForkExec
(substituir CXX pelo identificador do grupo)

A primeira tarefa a realizar, para prevenir conflitos de módulos Maven, é alterar todos os pom.xml para substituir as referências ao grupo CXX pelo identificador do grupo.
Preencher também todos os ficheiros README.md com a identificação do grupo e dos autores.

O servidor de restaurante tem um esqueleto funcional com a operação ctrlPing e tem um teste de integração. Agora, pretende-se ter múltiplos restaurantes e desenvolver também o serviço hub-ws que vai descobrir e comunicar com todos eles. Assim sendo, o UDDI torna-se útil e necessário.

Para começar, fazer a instalação do módulo principal.

Pretende-se agora confirmar que rst-ws UML se regista no UDDI.

  1. Confirmar a dependência para a biblioteca UDDINaming:
        ...
        <!-- UDDI Naming -->
        <dependency>
            <groupId>pt.ulisboa.tecnico.sdis</groupId>
            <artifactId>uddi-naming</artifactId>
            <version>1.2.0</version>
        </dependency>
        ...
    
  2. A RestaurantApp deverá receber o endereço do UDDI e o nome do serviço como argumento.
  3. O RestaurantEndpointManager deverá ter um construtor que recebe o endereço do UDDI e o nome do serviço, e que efetua o registo (e apaga quando o serviço termina).
  4. Feitas as alterações, o servidor deverá iniciar-se, registar-se no UDDI e depois ficar à espera de pedidos.

Lançar mais do que uma instância do rst-ws.

  1. A forma mais simples de permitir múltiplas instâncias da estação é parametrizar as propriedades de configuração com um número de instância.
  2. No pom.xml é possível ver as seguintes definições (substituir CXX pelo identificador do grupo):
        ...
        <ws.i>1</ws.i>
    
        <ws.host>localhost</ws.host>
        <ws.port>808${ws.i}</ws.port>
        <ws.url>http://${ws.host}:${ws.port}/rst-ws/endpoint</ws.url>
    
        <ws.name>CXX_Restaurant${ws.i}</ws.name>
        ...
    
  3. Para lançar um restaurante:
  4. Para lançar outro restaurante:

Pretende-se agora confirmar como rst-ws-cli UML pesquisa no UDDI.

  1. Confirmar a dependência para a biblioteca UDDINaming.
  2. O RestaurantClient deverá ter um construtor que recebe o endereço do UDDI e o nome do serviço a contactar, e que efetua a pesquisa para localizar o servidor.
  3. A RestaurantClientApp deverá receber o endereço do UDDI e o nome do serviço como argumento.

Hub

O ponto de partida inclui o servidor Hub incompleto (hub-ws) e o cliente incompleto (hub-ws-cli).

Vamos começar pelo servidor hub-ws:

  1. A estrutura do servidor está representada neste diagrama de classes UML.
    • O pacote à esquerda contém as classes que são geradas a partir do contrato WSDL.
    • O pacote à direita contém as classes do servidor:
      • a App onde a aplicação arranca,
      • o EndpointManager que disponibiliza o endereço do serviço,
      • o PortImpl que concretiza as operações definidas no WSDL, e
      • as classes de domínio que representam a informação armazenada pelo serviço.
  2. As classes de domínio da aplicação devem depois ser implementadas. Apenas existe o objeto inicial, o Domain root.
  3. De seguida, consultar o contrato WSDL do serviço a implementar:
  4. Vamos gerar código Java a partir do WSDL. O WSDL está na pasta hub-contract. O Maven está configurado para chamar a ferramenta wsimport.
    1. cd hub-ws
    2. 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.
    3. Faça refresh (right-click, Maven, Update Project..., Force Update of Snapshots/Releases, OK) 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.
  5. Vamos agora concretizar o serviço.
    1. Confirme que a classe de implementação do serviço ...PortImpl implementa a interface Java gerada.
    2. Confirmar a associação da 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. Para já vamos compilar e executar o servidor sem estas operações estarem concluídas. Coloque apenas um corpo vazio ou um retorno simples (e.g. return null).
  6. 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 hub-ws-cli para testar o servidor.

  1. A estrutura do cliente está representada neste diagrama de classes UML.
    • O pacote à direita contém as classes que são geradas a partir do contrato WSDL.
    • O pacote à esquerda contém as classes do servidor:
      • a ClientApp onde a aplicação arranca, e
      • o Client que usa o stub gerado para fazer invocações remotas.
    Existem também os testes de integração, em que cada classe de testes se destina a testar uma operação remota.
  2. 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
      • confirmar que a fase de wsimport está configurada.
    2. cd hub-ws-cli
    3. mvn generate-sources
      As classes são geradas na pasta: target/generated-sources/wsimport.
  3. Vamos fazer uma chamada simples, correndo a aplicação cliente.
  4. Depois do teste pontual, vamos correr os testes de integração já existentes.

Vamos agora implementar uma operação simples do servidor hub-ws que contacta as estações através de um ctrlPing.

  1. O hub-ws vai ser cliente de rst-ws.
    Em vez de repetir código, vamos usar o objeto RestaurantClient, já desenvolvido e testado.

    1. Em primeiro lugar, instalar o módulo do cliente do restaurante:
      cd rst-ws-cli
      mvn install
    2. Depois, acrescentar a dependência Maven no hub-ws/pom.xml (substituir CXX pelo identificador do grupo):
          ...
          <dependency>
              <groupId>com.forkexec.CXX</groupId>
              <artifactId>rst-ws-cli</artifactId>
              <version>1.0.0-SNAPSHOT</version>
          </dependency>
          ...
      
      O sistema em funcionamento terá três processos neste exercício:

  2. Concretizar a operação ctrlPing do Hub.

Finalmente, usar o hub-ws-cli para chamar o ctrlPing que vai fazer ping ao próprio Hub e a todos os restaurantes.

O que falta fazer?

Continuação de bom trabalho!


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