Labs SD >
O exemplo abaixo demonstra como configurar os tempos de espera pelas respostas de Web Services. No fim do tempo, caso a resposta não tenha sido recebida, é lançada uma exceção.
O JAX-WS distingue dois timeouts distintos:
Exemplo:
As operações unidirecionais de Web Service são aquelas que não enviam resposta, logo o programa cliente é desbloqueado mal a mensagem de pedido saia através da rede. Este exemplo demonstra como definir operações unidirecionais.
Até agora vimos exemplos de invocações remotas síncronas: o cliente faz um pedido ao servidor e fica bloqueado à espera da resposta. Caso o cliente não pretenda ficar bloqueado à espera da resposta do servidor, é possível fazê-lo através de uma invocação assíncrona. Neste caso o cliente faz o pedido, continua a executar, e vai receber a resposta mais tarde.
A forma de fazer invocações assíncronas é através dos métodos com sufixo Async. Para que estes métodos sejam gerados é necessário do lado do cliente indicar um ficheiro de binding, na pasta src/jaxws. Os stubs assim gerados passam a incluir tanto os métodos para invocação síncrona como assíncrona.
<bindings xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://java.sun.com/xml/ns/jaxws" > <bindings node="wsdl:definitions"> <enableAsyncMapping>true</enableAsyncMapping> </bindings> </bindings>
Existem duas formas alternativas de programar um cliente que recorre a chamadas assíncronas. De seguida explicamos cada uma.
Para uma invocação assíncrona, o cliente deve executar um método com o sufixo Async e de seguida usar o método Response.isDone() para verificar se a resposta já chegou. Nesta solução o cliente invoca o método remoto sem ficar bloqueado, ficando responsável por verificar, periodicamente, se o servidor já respondeu (através do objecto Response). Só depois da resposta ter chegado, pode então o cliente obter o seu resultado através do objecto Response.
// asynchronous call with polling Response<EchoResponse> response = port.echoAsync(name); while (!response.isDone()) { Thread.sleep(10 /* milliseconds */); /* while waiting for response do something else... */ System.out.print("."); System.out.flush(); } System.out.print("Asynchronous call result: "); System.out.println(response.get().getReturn());
Um outro modelo de funcionamento é o registo de um objecto de callback do tipo AsyncHandler aquando da execução da chamada assíncrona. Quando a resposta chega, um método desse objeto é invocado. Este funcionamento é semelhante ao atendimento de interrupções num processador. A rotina de callback corresponde à rotina de atendimento da interrupção. O receber uma resposta do servidor corresponde à interrupção.
static boolean finished = false; ... // asynchronous call with callback port.echoAsync(name, new AsyncHandler() { @Override public void handleResponse(Response response) { try { System.out.println(); System.out.print("Asynchronous call result arrived: "); System.out.println(response.get().getReturn()); finished = true; } catch (InterruptedException e) { System.out.println("Caught interrupted exception."); System.out.print("Cause: "); System.out.println(e.getCause()); } catch (ExecutionException e) { System.out.println("Caught execution exception."); System.out.print("Cause: "); System.out.println(e.getCause()); } } }); while (!finished) { // do something else while waiting.. Thread.sleep(10 /* milliseconds */); System.out.print("."); System.out.flush(); }
Em ambos os casos, a resposta é obtida invocando o método response.get(), que pode lançar uma exceção caso esta tenha sido retornada pelo método remoto. Caso o método remoto retorne Void, este método lançará uma NullPointerException. Caso contrário, o objecto retornado pode ser obtido com o método getReturn().
Consultar o exemplo de cliente-servidor com invocações assíncronas:
Repare que não é preciso alterar o servidor para que o cliente possa fazer invocações assíncronas. Apenas é necessário um stub diferente.
O objetivo deste exercício é adaptar o código do módulo pts do projeto de forma a que as chamadas passem a ser feitas assincronamente. Como será discutido nas aulas teóricas, esta extensão permitirá implementar o protocolo de replicação da segunda parte do projeto de forma mais eficiente. Hoje estamos a aprender a técnica das chamadas assíncronas.
public class PointsClient {Este passo evita ter que implementar os métodos assíncronos para todas as operações.
public Response<PointsBalanceResponse> pointsBalanceAsync(String userEmail) { return port.pointsBalanceAsync(userEmail); }
import javax.xml.ws.Response; import java.util.concurrent.ExecutionException; // ... (acrescentar no fim do método) String userEmail = "user@example.com"; client.activateUser(userEmail); // asynchronous call with polling Response<PointsBalanceResponse> response = client.pointsBalanceAsync(userEmail); while (!response.isDone()) { Thread.sleep(10 /* milliseconds */); System.out.print("."); System.out.flush(); } try { System.out.println("(Polling) asynchronous call result: " + response.get().getReturn()); } catch (ExecutionException e) { System.out.println("Caught execution exception."); System.out.print("Cause: "); System.out.println(e.getCause()); }
public Future<?> pointsBalanceAsync(String userEmail, AsyncHandler<PointsBalanceResponse> asyncHandler) { return port.pointsBalanceAsync(userEmail, asyncHandler); }
import javax.xml.ws.Response; public class PointsClientApp { static boolean received = false; public static void main(String[] args) throws Exception { // ... (acrescentar no fim do método) String userEmail1 = "user@example.com"; client.activateUser(userEmail1); client.addPoints(userEmail1, 1100); // asynchronous call with callback client.pointsBalanceAsync(userEmail1, new AsyncHandler<PointsBalanceResponse>() { @Override public void handleResponse(Response<PointsBalanceResponse> response) { try { System.out.println(); System.out.print("(Callback) Asynchronous call result arrived: "); System.out.println(response.get().getReturn()); received = true; } catch (InterruptedException e) { System.out.println("Caught interrupted exception."); System.out.print("Cause: "); System.out.println(e.getCause()); } catch (ExecutionException e) { System.out.println("Caught execution exception."); System.out.print("Cause: "); System.out.println(e.getCause()); } } }); while (!received) { Thread.sleep(10 /* milliseconds */); System.out.print("."); System.out.flush(); }
© Docentes de Sistemas Distribuídos,
Dep. Eng. Informática,
Técnico Lisboa