【Java】【JAX-WS】 Webサービス / Metro [9] ~ タイムアウトを設定する / クライアントサイド ~

■ はじめに

 * 以下の Metro のユーザズガイド
https://metro.java.net/1.5/guide/HTTP_Timeouts.html
に従って、以下【ダメだった例】のように実装したが、タイムアウトが発生しなかった。
# サーバが、GlassFishじゃなかったから?

ただ、タイムアウトを実現できたので、メモしておく

【ダメだった例】タイムアウトが発生しなかった実装

Map<String, Object> context = ((BindingProvider)proxy).getRequestContext();

// 接続にかかった時間
context.put("com.sun.xml.ws.request.timeout", 2 * 1000);

// データ取得にかかった時間
context.put("com.sun.xml.ws.request.timeout", 2 * 1000);
JAXWSProperties.CONNECT_TIMEOUT について
https://jax-ws.java.net/nonav/jax-ws-20-fcs/arch/constant-values.html#com.sun.xml.ws.developer.JAXWSProperties.CONNECT_TIMEOUT

■ ポイント

Map<String, Object> context = ((BindingProvider) proxy).getRequestContext();

// 接続にかかった時間[ミリ秒]
context.put("com.sun.xml.internal.ws.request.timeout", 2 * 1000);

// データ取得にかかった時間[ミリ秒]
context.put("com.sun.xml.internal.ws.connect.timeout", 2 * 1000);

補足

 * ただし、この方法では、WSDLファイル取得時のタイムアウトにはならない。
   詳細および解決案などについて、以下の関連記事を参照。
Webサービス / Metro [10] ~ WSDLファイルをクライアントのローカルに置く ~
https://blogs.yahoo.co.jp/dk521123/36872164.html

■ サンプル

動作環境

 * Windows10
 * Java1.8
 * Eclipse Mars.2 Release (4.5.2)
 * Tomcat v8.5.8
 * metro-2.3.1

サーバ側

http://blogs.yahoo.co.jp/dk521123/36139336.html
をベースに...
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.xml.bind.annotation.XmlElement;

@WebService(name = "SampleWebService")
public class SampleWebService {
  @WebMethod
  public String sayYourAge(@XmlElement(required = true, nillable = false) @WebParam(name = "name") String name,
      @XmlElement(required = false, nillable = true) @WebParam(name = "age") Long age) {

    // ★ここで、実験のため、意図的にサーバ側に時間が掛かるようにした★
    try {
      Thread.sleep(10 * 1000L);
    } catch (InterruptedException ex) {
      ex.printStackTrace();
    }

    return name + "'s age is " + age + ".";
  }
}

クライアント側

http://blogs.yahoo.co.jp/dk521123/36140561.html
をベースに...
import java.net.URL;
import java.util.Map;

import javax.xml.ws.BindingProvider;

public class Main {

  public static void main(String[] args) {
    System.out.println("Start!");

    try {
      URL url = new URL("http://localhost:8080/SampleWebService/services/SampleWebService.ws?wsdl");
      SampleWebServiceService service = new SampleWebServiceService(url);
      SampleWebService proxy = service.getSampleWebServicePort();

      // ★ここ★
      Map<String, Object> context = ((BindingProvider) proxy).getRequestContext();
      // 接続にかかった時間[ミリ秒]
      context.put("com.sun.xml.internal.ws.request.timeout", 2 * 1000);
      // データ取得にかかった時間[ミリ秒]
      context.put("com.sun.xml.internal.ws.connect.timeout", 2 * 1000);

      long start = System.currentTimeMillis();
      String result = proxy.sayYourAge("Ken", 11L);
      long end = System.currentTimeMillis();
      System.out.println((end - start) + "ms");
      
      System.out.println("Result : " + result);
    } catch (Exception ex) {
      ex.printStackTrace();
    }
    System.out.println("Done");
  }
}

出力結果

Start!
javax.xml.ws.WebServiceException: java.net.SocketTimeoutException: Read timed out
	at com.sun.xml.internal.ws.transport.http.client.HttpClientTransport.readResponseCodeAndMessage(HttpClientTransport.java:195)
	at com.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.createResponsePacket(HttpTransportPipe.java:226)
	at com.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.process(HttpTransportPipe.java:217)
	at com.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.processRequest(HttpTransportPipe.java:130)
	at com.sun.xml.internal.ws.transport.DeferredTransportPipe.processRequest(DeferredTransportPipe.java:95)
	at com.sun.xml.internal.ws.api.pipe.Fiber.__doRun(Fiber.java:1121)
	at com.sun.xml.internal.ws.api.pipe.Fiber._doRun(Fiber.java:1035)
	at com.sun.xml.internal.ws.api.pipe.Fiber.doRun(Fiber.java:1004)
	at com.sun.xml.internal.ws.api.pipe.Fiber.runSync(Fiber.java:862)
	at com.sun.xml.internal.ws.client.Stub.process(Stub.java:448)
	at com.sun.xml.internal.ws.client.sei.SEIStub.doProcess(SEIStub.java:178)
	at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:93)
	at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:77)
	at com.sun.xml.internal.ws.client.sei.SEIStub.invoke(SEIStub.java:147)
	at com.sun.proxy.$Proxy35.sayYourAge(Unknown Source)
	at com.sample.webservice.client.stub.Main2.main(Main2.java:29)
	... 15 more
Done

■ あとがき

今回、Webサービスのアクセスする際にタイムアウト値を設けたが、
場合によって、時間がかかる場合があった。
その解決案は、以下の関連記事を記載してある
https://blogs.yahoo.co.jp/dk521123/36904908.html


関連記事

Webサービス / Metro [1] ~入門編 / サーバサイドの構築 ~

http://blogs.yahoo.co.jp/dk521123/36139336.html

Webサービス / Metro [2] ~入門編 / クライアントサイドの構築 ~

http://blogs.yahoo.co.jp/dk521123/36140561.html

Webサービス / Metro [5] ~応用編 / あれこれ ~

http://blogs.yahoo.co.jp/dk521123/36238319.html

Webサービス / Metro [10] ~ WSDLファイルをクライアントのローカルに置く ~

https://blogs.yahoo.co.jp/dk521123/36872164.html

Debian で、DNSタイムアウトを設定する

https://blogs.yahoo.co.jp/dk521123/36904908.html